home *** CD-ROM | disk | FTP | other *** search
- /*
- * qstat 2.5b
- * by Steve Jankowski
- * steve@qstat.org
- * http://www.qstat.org
- *
- * Thanks to Per Hammer for the OS/2 patches (per@mindbend.demon.co.uk)
- * Thanks to John Ross Hunt for the OpenVMS Alpha patches (bigboote@ais.net)
- * Thanks to Scott MacFiggen for the quicksort code (smf@webmethods.com)
- * Thanks to Simon Garner for the XML patch (sgarner@gameplanet.co.nz)
- *
- * Inspired by QuakePing by Len Norton
- *
- * Copyright 1996,1997,1998,1999 by Steve Jankowski
- *
- * Licensed under the Artistic License, see LICENSE.txt for license terms
- */
-
- #define VERSION "2.5b"
- char *qstat_version= VERSION;
-
- /* OS/2 defines */
- #ifdef __OS2__
- #define BSD_SELECT
- #endif
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <string.h>
- #include <ctype.h>
-
- #define QUERY_PACKETS
- #include "qstat.h"
- #include "config.h"
-
-
- #ifdef _ISUNIX
- #include <unistd.h>
- #include <sys/socket.h>
- #ifndef VMS
- #include <sys/param.h>
- #endif
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <netinet/tcp.h>
- #include <netdb.h>
- #include <arpa/inet.h>
-
- #ifndef F_SETFL
- #include <fcntl.h>
- #endif
-
- #ifdef __hpux
- extern int h_errno;
- #define STATIC static
- #else
- #define STATIC
- #endif
-
- #define INVALID_SOCKET -1
- #define SOCKET_ERROR -1
- #ifndef INADDR_NONE
- #define INADDR_NONE ~0
- #endif
- #define sockerr() errno
- #endif /* _ISUNIX */
-
- #ifdef _WIN32
- #ifndef FD_SETSIZE
- #define FD_SETSIZE 256
- #endif
- #include <winsock.h>
- #include <sys/timeb.h>
- #define close(a) closesocket(a)
- int gettimeofday(struct timeval *now, void *blah)
- {
- struct timeb timeb;
- ftime( &timeb);
- now->tv_sec= timeb.time;
- now->tv_usec= (unsigned int)timeb.millitm * 1000;
- return 0;
- }
- #define sockerr() WSAGetLastError()
- #define strcasecmp stricmp
- #define strncasecmp strnicmp
- #define STATIC
- #ifndef EADDRINUSE
- #define EADDRINUSE WSAEADDRINUSE
- #endif
- #endif /* _WIN32 */
-
- #ifdef __OS2__
- #include <sys/socket.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <utils.h>
-
- #define INVALID_SOCKET -1
- #define SOCKET_ERROR -1
- #define close(a) soclose(a)
- #endif /* __OS2__ */
-
-
- #ifndef FD_SETSIZE
- #define FD_SETSIZE 64
- #endif
-
- /* Figure out whether to use poll() or select()
- */
- #ifndef USE_POLL
- #ifndef USE_SELECT
-
- #ifdef sun
- #define USE_POLL
- #endif
- #ifdef linux
- #define USE_POLL
- #include <poll.h>
- #endif
- #ifdef __linux__
- #define USE_POLL
- #include <poll.h>
- #endif
- #ifdef __linux
- #define USE_POLL
- #include <poll.h>
- #endif
- #ifdef __hpux
- #define USE_POLL
- #include <sys/poll.h>
- #endif
- #ifdef __OpenBSD__
- #define USE_POLL
- #include <sys/poll.h>
- #endif
- #ifdef _AIX
- #define USE_POLL
- #include <poll.h>
- #endif
- #ifdef _WIN32
- #define USE_SELECT
- #endif
- #ifdef __EMX__
- #define USE_SELECT
- #endif
-
- #endif
- #endif
-
- /* If did not chose, then use select()
- */
- #ifndef USE_POLL
- #ifndef USE_SELECT
- #define USE_SELECT
- #endif
- #endif
-
- server_type *types;
- int n_server_types;
-
- /* Values set by command-line arguments
- */
-
-
- int hostname_lookup= 0; /* set if -H was specified */
- int new_style= 1; /* unset if -old was specified */
- int n_retries= DEFAULT_RETRIES;
- int retry_interval= DEFAULT_RETRY_INTERVAL;
- int master_retry_interval= DEFAULT_RETRY_INTERVAL*4;
- int get_player_info= 0;
- int get_server_rules= 0;
- int up_servers_only= 0;
- int no_full_servers= 0;
- int no_empty_servers= 0;
- int no_header_display= 0;
- int raw_display= 0;
- char *raw_delimiter= "\t";
- int player_address= 0;
- int hex_player_names= 0;
- int strip_carets= 1;
- int max_simultaneous= MAXFD_DEFAULT;
- int html_names= -1;
- extern int html_mode;
- int raw_arg= 0;
- int show_game_in_raw= 0;
- int progress= 0;
- int num_servers_total= 0;
- int num_players_total= 0;
- int num_servers_returned= 0;
- int num_servers_timed_out= 0;
- int num_servers_down= 0;
- server_type* default_server_type= NULL;
- FILE *OF; /* output file */
- unsigned int source_ip= INADDR_ANY;
- unsigned short source_port_low= 0;
- unsigned short source_port_high= 0;
- unsigned short source_port= 0;
-
- #define ENCODING_LATIN_1 1
- #define ENCODING_UTF_8 8
- int xml_display= 0;
- int xml_encoding= ENCODING_LATIN_1;
-
- #define SUPPORTED_SERVER_SORT "pgihn"
- #define SUPPORTED_PLAYER_SORT "PFT"
- #define SUPPORTED_SORT_KEYS "l" SUPPORTED_SERVER_SORT SUPPORTED_PLAYER_SORT
- char sort_keys[32];
- int player_sort= 0;
- int server_sort= 0;
-
- void sort_servers( struct qserver **array, int size);
- void sort_players( struct qserver *server);
- int server_compare( struct qserver *one, struct qserver *two);
- int player_compare( struct player *one, struct player *two);
-
- int show_errors= 0;
-
- #define DEFAULT_COLOR_NAMES_RAW 0
- #define DEFAULT_COLOR_NAMES_DISPLAY 1
- int color_names= -1;
-
- #define SECONDS 0
- #define CLOCK_TIME 1
- #define STOPWATCH_TIME 2
- #define DEFAULT_TIME_FMT_RAW SECONDS
- #define DEFAULT_TIME_FMT_DISPLAY CLOCK_TIME
- int time_format= -1;
-
- struct qserver *servers= NULL;
- struct qserver **last_server= &servers;
- struct qserver **connmap= NULL;
- int max_connmap;
- struct qserver *last_server_bind= NULL;
- int connected= 0;
- time_t run_timeout= 0;
- time_t start_time;
- int waiting_for_masters;
-
- #define ADDRESS_HASH_LENGTH 503
- static struct qserver **server_hash[ADDRESS_HASH_LENGTH];
- static unsigned int server_hash_len[ADDRESS_HASH_LENGTH];
-
- char *DOWN= "DOWN";
- char *SYSERROR= "SYSERROR";
- char *TIMEOUT= "TIMEOUT";
- char *MASTER= "MASTER";
- char *SERVERERROR= "ERROR";
- char *HOSTNOTFOUND= "HOSTNOTFOUND";
-
- int display_prefix= 0;
- char *current_filename;
- int current_fileline;
-
- int count_bits( int n);
-
- static int wait_for_timeout( unsigned int ms);
- static void finish_output();
- static void decode_stefmaster_packet( struct qserver *server, char *pkt, int pktlen);
- static void decode_q3master_packet( struct qserver *server, char *pkt, int pktlen);
- static int combine_packets( struct qserver *server);
- static int unreal_player_info_key( char *s, char *end);
-
-
-
- struct rule * add_rule( struct qserver *server, char *key, char *value,
- int flags);
- #define NO_FLAGS 0
- #define NO_VALUE_COPY 1
- #define CHECK_DUPLICATE_RULES 2
-
- /* MODIFY HERE
- * Change these functions to display however you want
- */
- void
- display_server(
- struct qserver *server
- )
- {
- char name[100], prefix[64];
-
- if ( player_sort)
- sort_players( server);
-
- if ( raw_display) {
- raw_display_server( server);
- return;
- }
- else if ( xml_display) {
- xml_display_server( server);
- return;
- }
- if ( have_server_template()) {
- template_display_server( server);
- return;
- }
-
- if ( display_prefix)
- sprintf( prefix, "%-4s ", server->type->type_prefix);
- else
- prefix[0]='\0';
-
- if ( server->server_name == DOWN) {
- if ( ! up_servers_only)
- fprintf( OF, "%s%-16s %10s\n", prefix,
- (hostname_lookup) ? server->host_name : server->arg, DOWN);
- return;
- }
- if ( server->server_name == TIMEOUT) {
- if ( server->flags & FLAG_BROADCAST && server->n_servers)
- fprintf( OF, "%s%-16s %d servers\n", prefix,
- server->arg, server->n_servers);
- else if ( ! up_servers_only)
- fprintf( OF, "%s%-16s no response\n", prefix,
- (hostname_lookup) ? server->host_name : server->arg);
- return;
- }
-
- if ( server->type->master) {
- display_qwmaster(server);
- return;
- }
-
- if ( no_full_servers && server->num_players >= server->max_players)
- return;
-
- if ( no_empty_servers && server->num_players == 0)
- return;
-
- if ( server->error != NULL) {
- fprintf( OF, "%s%-21s ERROR <%s>\n",
- prefix,
- (hostname_lookup) ? server->host_name : server->arg,
- server->error);
- return;
- }
-
- if ( new_style) {
- char *game= get_qw_game( server);
- int map_name_width= 8, game_width=0;
- switch( server->type->id) {
- case QW_SERVER: case Q2_SERVER: case Q3_SERVER:
- game_width= 9; break;
- case TRIBES2_SERVER:
- map_name_width= 14; game_width= 8; break;
- case HL_SERVER:
- map_name_width= 12; break;
- default:
- break;
- }
- fprintf( OF, "%s%-21s %2d/%2d %*s %6d / %1d %*s %s\n",
- prefix,
- (hostname_lookup) ? server->host_name : server->arg,
- server->num_players, server->max_players,
- map_name_width, (server->map_name) ? server->map_name : "?",
- server->ping_total/server->n_requests,
- server->n_retries,
- game_width, game,
- xform_name(server->server_name, server));
- if ( get_server_rules)
- server->type->display_rule_func( server);
- if ( get_player_info)
- server->type->display_player_func( server);
- }
- else {
- sprintf( name, "\"%s\"", server->server_name);
- fprintf( OF, "%-16s %10s map %s at %22s %d/%d players %d ms\n",
- (hostname_lookup) ? server->host_name : server->arg,
- name, server->map_name,
- server->address, server->num_players, server->max_players,
- server->ping_total/server->n_requests);
- }
- }
-
- void
- display_qwmaster( struct qserver *server)
- {
- char *prefix;
- prefix= server->type->type_prefix;
-
- if ( server->error != NULL)
- fprintf( OF, "%s %-17s ERROR <%s>\n", prefix,
- (hostname_lookup) ? server->host_name : server->arg,
- server->error);
- else
- fprintf( OF, "%s %-17s %d servers %6d / %1d\n", prefix,
- (hostname_lookup) ? server->host_name : server->arg,
- server->n_servers,
- server->ping_total/server->n_requests,
- server->n_retries);
- }
-
- void
- display_header()
- {
- if ( ! no_header_display)
- fprintf( OF, "%-16s %8s %8s %15s %s\n", "ADDRESS", "PLAYERS", "MAP",
- "RESPONSE TIME", "NAME");
- }
-
- void
- display_server_rules( struct qserver *server)
- {
- struct rule *rule;
- int printed= 0;
- rule= server->rules;
- for ( ; rule != NULL; rule= rule->next) {
- if ( (server->type->id != Q_SERVER &&
- server->type->id != H2_SERVER) || ! is_default_rule( rule)) {
- fprintf( OF, "%c%s=%s", (printed)?',':'\t', rule->name, rule->value);
- printed++;
- }
- }
- if ( printed)
- fputs( "\n", OF);
- }
-
- void
- display_q_player_info( struct qserver *server)
- {
- char fmt[128];
- struct player *player;
-
- strcpy( fmt, "\t#%-2d %3d frags %9s ");
-
- if ( color_names)
- strcat( fmt, "%9s:%-9s ");
- else
- strcat( fmt, "%2d:%-2d ");
- if ( player_address)
- strcat( fmt, "%22s ");
- else
- strcat( fmt, "%s");
- strcat( fmt, "%s\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- player->number,
- player->frags,
- play_time(player->connect_time,1),
- quake_color(player->shirt_color),
- quake_color(player->pants_color),
- (player_address)?player->address:"",
- xform_name( player->name, server));
- }
- }
-
- void
- display_qw_player_info( struct qserver *server)
- {
- char fmt[128];
- struct player *player;
-
- strcpy( fmt, "\t#%-6d %3d frags %6s@%-5s %8s");
-
- if ( color_names)
- strcat( fmt, "%9s:%-9s ");
- else
- strcat( fmt, "%2d:%-2d ");
- strcat( fmt, "%s\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- player->number,
- player->frags,
- play_time(player->connect_time,0),
- ping_time(player->ping),
- player->skin ? player->skin : "",
- quake_color(player->shirt_color),
- quake_color(player->pants_color),
- xform_name( player->name, server));
- }
- }
-
- void
- display_q2_player_info( struct qserver *server)
- {
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- if ( server->flags & FLAG_PLAYER_TEAMS)
- fprintf( OF, "\t%3d frags team#%d %8s %s\n",
- player->frags,
- player->team,
- ping_time(player->ping),
- xform_name( player->name, server));
- else
- fprintf( OF, "\t%3d frags %8s %s\n",
- player->frags,
- ping_time(player->ping),
- xform_name( player->name, server));
- }
- }
-
- void
- display_unreal_player_info( struct qserver *server)
- {
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, "\t%3d frags team#%-3d %7s %s\n",
- player->frags,
- player->team,
- ping_time(player->ping),
- xform_name( player->name, server));
- }
- }
-
- void
- display_shogo_player_info( struct qserver *server)
- {
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, "\t%3d frags %8s %s\n",
- player->frags,
- ping_time(player->ping),
- xform_name( player->name, server));
- }
- }
-
- void
- display_halflife_player_info( struct qserver *server)
- {
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, "\t%3d frags %8s %s\n",
- player->frags,
- play_time( player->connect_time,1),
- xform_name( player->name, server));
- }
- }
-
- void
- display_tribes_player_info( struct qserver *server)
- {
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, "\t%4d score team#%d %8s %s\n",
- player->frags,
- player->team,
- ping_time( player->ping),
- xform_name( player->name, server));
- }
- }
-
- void
- display_tribes2_player_info( struct qserver *server)
- {
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, "\tscore %4d %14s %s\n",
- player->frags,
- player->team_name ? player->team_name : (player->number == TRIBES_TEAM ? "TEAM" : "?"),
- xform_name( player->name, server));
- }
- }
-
- void
- display_bfris_player_info( struct qserver *server)
- {
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, "\ttid: %d, ship: %d, team: %s, ping: %d, score: %d, kills: %d, name: %s\n",
- player->number,
- player->ship,
- player->team_name,
- player->ping,
- player->score,
- player->frags,
- xform_name( player->name, server));
- }
- }
-
- void
- display_descent3_player_info( struct qserver *server)
- {
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, "\t%3d frags %3d deaths team#%-3d %7s %s\n",
- player->frags,
- player->deaths,
- player->team,
- ping_time(player->ping),
- xform_name( player->name, server));
- }
- }
-
- char *
- get_qw_game( struct qserver *server)
- {
- struct rule *rule;
- if ( server->type->game_rule == NULL || *server->type->game_rule == '\0')
- return "";
- rule= server->rules;
- for ( ; rule != NULL; rule= rule->next)
- if ( strcmp( rule->name, server->type->game_rule) == 0) {
- if ( server->type->id == Q3_SERVER &&
- strcmp( rule->value, "baseq3") == 0)
- return "";
- return rule->value;
- }
- rule= server->rules;
- for ( ; rule != NULL; rule= rule->next)
- if ( strcmp( rule->name, "game") == 0)
- return rule->value;
- return "";
- }
-
- /* Raw output for web master types
- */
-
- #define RD raw_delimiter
-
- void
- raw_display_server( struct qserver *server)
- {
- char *prefix;
- int ping_time;
- prefix= server->type->type_prefix;
-
- if ( server->n_requests)
- ping_time= server->ping_total/server->n_requests;
- else
- ping_time= 0;
-
- if ( server->server_name == DOWN) {
- if ( ! up_servers_only)
- fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s\n\n",
- prefix,
- raw_arg, RD, raw_arg, server->arg,
- RD, (hostname_lookup)?server->host_name:server->arg,
- RD, DOWN);
- return;
- }
- if ( server->server_name == TIMEOUT) {
- if ( server->flags & FLAG_BROADCAST && server->n_servers)
- fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%d\n", prefix,
- raw_arg, RD, raw_arg, server->arg,
- RD, server->arg,
- RD, server->n_servers);
- else if ( ! up_servers_only)
- fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s\n\n",
- prefix,
- raw_arg, RD, raw_arg, server->arg,
- RD, (hostname_lookup)?server->host_name:server->arg,
- RD, TIMEOUT);
- return;
- }
-
- if ( server->error != NULL) {
- fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s",
- prefix,
- raw_arg, RD, raw_arg, server->arg,
- RD, (hostname_lookup) ? server->host_name : server->arg,
- RD, "ERROR",
- RD, server->error);
- }
- else if ( server->type->flags & TF_RAW_STYLE_QUAKE) {
- fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%s" "%s%d" "%s%d" "%s%d" "%s%d" "%s%s",
- prefix,
- raw_arg, RD, raw_arg, server->arg,
- RD, (hostname_lookup) ? server->host_name : server->arg,
- RD, xform_name( server->server_name, server),
- RD, server->address,
- RD, server->protocol_version,
- RD, server->map_name,
- RD, server->max_players,
- RD, server->num_players,
- RD, ping_time,
- RD, server->n_retries,
- show_game_in_raw ? RD : "", show_game_in_raw ? get_qw_game(server) : ""
- );
- }
- else if ( server->type->flags & TF_RAW_STYLE_TRIBES) {
- fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%d",
- prefix,
- raw_arg, RD, raw_arg, server->arg,
- RD, (hostname_lookup) ? server->host_name : server->arg,
- RD, xform_name( server->server_name, server),
- RD, (server->map_name) ? server->map_name : "?",
- RD, server->num_players,
- RD, server->max_players
- );
- }
- else if ( server->type->master) {
- fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%d",
- prefix,
- raw_arg, RD, raw_arg, server->arg,
- RD, (hostname_lookup) ? server->host_name : server->arg,
- RD, server->n_servers
- );
- }
- else {
- fprintf( OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%d" "%s%d" "%s%d" "%s%s",
- prefix,
- raw_arg, RD, raw_arg, server->arg,
- RD, (hostname_lookup) ? server->host_name : server->arg,
- RD, xform_name( server->server_name, server),
- RD, (server->map_name) ? server->map_name : "?",
- RD, server->max_players,
- RD, server->num_players,
- RD, ping_time,
- RD, server->n_retries,
- show_game_in_raw ? RD : "", show_game_in_raw ? get_qw_game(server) : ""
- );
- }
- fputs( "\n", OF);
-
- if ( server->type->master || server->error != NULL) {
- fputs( "\n", OF);
- return;
- }
-
- if ( get_server_rules)
- server->type->display_raw_rule_func( server);
- if ( get_player_info)
- server->type->display_raw_player_func( server);
- fputs( "\n", OF);
- }
-
- void
- raw_display_server_rules( struct qserver *server)
- {
- struct rule *rule;
- int printed= 0;
- rule= server->rules;
- for ( ; rule != NULL; rule= rule->next) {
- if ( server->type->id == TRIBES2_SERVER) {
- char *v;
- for ( v= rule->value; *v; v++)
- if ( *v == '\n') *v= ' ';
- }
- fprintf( OF, "%s%s=%s", (printed)?RD:"", rule->name, rule->value);
- printed++;
- }
- if ( server->missing_rules)
- fprintf( OF, "%s?", (printed)?RD:"");
- fputs( "\n", OF);
- }
-
- void
- raw_display_q_player_info( struct qserver *server)
- {
- char fmt[128];
- struct player *player;
-
- strcpy( fmt, "%d" "%s%s" "%s%s" "%s%d" "%s%s");
- if ( color_names)
- strcat( fmt, "%s%s" "%s%s");
- else
- strcat( fmt, "%s%d" "%s%d");
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- player->number,
- RD, xform_name( player->name, server),
- RD, player->address,
- RD, player->frags,
- RD, play_time(player->connect_time,1),
- RD, quake_color(player->shirt_color),
- RD, quake_color(player->pants_color)
- );
- fputs( "\n", OF);
- }
- }
-
- void
- raw_display_qw_player_info( struct qserver *server)
- {
- char fmt[128];
- struct player *player;
-
- strcpy( fmt, "%d" "%s%s" "%s%d" "%s%s");
- if ( color_names)
- strcat( fmt, "%s%s" "%s%s");
- else
- strcat( fmt, "%s%d" "%s%d");
- strcat( fmt, "%s%d" "%s%s");
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- player->number,
- RD, xform_name( player->name, server),
- RD, player->frags,
- RD, play_time(player->connect_time,1),
- RD, quake_color(player->shirt_color),
- RD, quake_color(player->pants_color),
- RD, player->ping,
- RD, player->skin ? player->skin : ""
- );
- fputs( "\n", OF);
- }
- }
-
- void
- raw_display_q2_player_info( struct qserver *server)
- {
- static char fmt[24] = "%s" "%s%d" "%s%d";
- static char fmt_team[24] = "%s" "%s%d" "%s%d" "%s%d";
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- if ( server->flags & FLAG_PLAYER_TEAMS)
- fprintf( OF, fmt_team,
- xform_name( player->name, server),
- RD, player->frags,
- RD, player->ping,
- RD, player->team
- );
- else
- fprintf( OF, fmt,
- xform_name( player->name, server),
- RD, player->frags,
- RD, player->ping
- );
- fputs( "\n", OF);
- }
- }
-
- void
- raw_display_unreal_player_info( struct qserver *server)
- {
- static char fmt[28]= "%s" "%s%d" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- xform_name( player->name, server),
- RD, player->frags,
- RD, player->ping,
- RD, player->team,
- RD, player->skin ? player->skin : "",
- RD, player->mesh ? player->mesh : "",
- RD, player->face ? player->face : ""
- );
- fputs( "\n", OF);
- }
- }
-
- void
- raw_display_halflife_player_info( struct qserver *server)
- {
- static char fmt[24]= "%s" "%s%d" "%s%s";
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- xform_name( player->name, server),
- RD, player->frags,
- RD, play_time( player->connect_time,1)
- );
- fputs( "\n", OF);
- }
- }
-
- void
- raw_display_tribes_player_info( struct qserver *server)
- {
- static char fmt[24]= "%s" "%s%d" "%s%d" "%s%d" "%s%d";
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- xform_name( player->name, server),
- RD, player->frags,
- RD, player->ping,
- RD, player->team,
- RD, player->packet_loss
- );
- fputs( "\n", OF);
- }
- }
-
- void
- raw_display_tribes2_player_info( struct qserver *server)
- {
- static char fmt[]= "%s" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
- struct player *player;
- char *type;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- switch( player->type_flag) {
- case PLAYER_TYPE_BOT: type= "Bot"; break;
- case PLAYER_TYPE_ALIAS: type= "Alias"; break;
- default: type= ""; break;
- }
- fprintf( OF, fmt,
- xform_name( player->name, server),
- RD, player->frags,
- RD, player->team,
- RD, player->team_name ? player->team_name : "TEAM",
- RD, type,
- RD, player->tribe_tag ? xform_name(player->tribe_tag,server) : ""
- );
- fputs( "\n", OF);
- }
- }
-
- void
- raw_display_bfris_player_info( struct qserver *server)
- {
- static char fmt[] = "%d" "%s%d" "%s%s" "%s%d" "%s%d" "%s%d" "%s%s";
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- player->number,
- RD, player->ship,
- RD, player->team_name,
- RD, player->ping,
- RD, player->score,
- RD, player->frags,
- RD, xform_name( player->name, server)
- );
- fputs( "\n", OF);
- }
- }
-
- void
- raw_display_descent3_player_info( struct qserver *server)
- {
- static char fmt[28]= "%s" "%s%d" "%s%d" "%s%d" "%s%d";
- struct player *player;
-
- player= server->players;
- for ( ; player != NULL; player= player->next) {
- fprintf( OF, fmt,
- xform_name( player->name, server),
- RD, player->frags,
- RD, player->deaths,
- RD, player->ping,
- RD, player->team
- );
- fputs( "\n", OF);
- }
- }
-
-
-
- /* XML output
- * Contributed by <sgarner@gameplanet.co.nz> :-)
- */
-
- void
- xml_display_server( struct qserver *server)
- {
- char *prefix;
- int server_type= server->type->id;
- prefix= server->type->type_prefix;
-
- if ( server->server_name == DOWN)
- {
- if ( ! up_servers_only)
- {
- fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n",
- xml_escape(prefix), xml_escape(server->arg), xml_escape(DOWN));
- fprintf( OF, "\t\t<hostname>%s</hostname>\n",
- xml_escape((hostname_lookup)?server->host_name:server->arg));
- fprintf( OF, "\t</server>\n");
- }
- return;
- }
- if ( server->server_name == TIMEOUT)
- {
- if ( server->flags & FLAG_BROADCAST && server->n_servers)
- {
- fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\" servers=\"%d\">\n",
- xml_escape(prefix), xml_escape(server->arg),
- xml_escape(TIMEOUT), server->n_servers);
- fprintf( OF, "\t</server>\n");
- }
- else if ( ! up_servers_only)
- {
- fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n",
- xml_escape(prefix), xml_escape(server->arg), xml_escape(TIMEOUT));
- fprintf( OF, "\t\t<hostname>%s</hostname>\n",
- xml_escape((hostname_lookup)?server->host_name:server->arg));
- fprintf( OF, "\t</server>\n");
- }
- return;
- }
-
- if ( server->error != NULL)
- {
- fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n",
- xml_escape(prefix), xml_escape(server->arg), "ERROR");
- fprintf( OF, "\t\t<hostname>%s</hostname>\n",
- xml_escape((hostname_lookup)?server->host_name:server->arg));
- fprintf( OF, "\t\t<error>%s</error>\n",
- xml_escape(server->error));
- }
- else if ( server->type->master)
- {
- fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\" servers=\"%d\">\n",
- xml_escape(prefix), xml_escape(server->arg), "UP", server->n_servers);
- }
- else {
- fprintf( OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n",
- xml_escape(prefix), xml_escape(server->arg), "UP");
- fprintf( OF, "\t\t<hostname>%s</hostname>\n",
- xml_escape((hostname_lookup)?server->host_name:server->arg));
- fprintf( OF, "\t\t<name>%s</name>\n",
- xml_escape(xform_name( server->server_name, server)));
- fprintf( OF, "\t\t<gametype>%s</gametype>\n",
- xml_escape(get_qw_game(server)));
- fprintf( OF, "\t\t<map>%s</map>\n",
- xml_escape(server->map_name));
- fprintf( OF, "\t\t<numplayers>%d</numplayers>\n",
- server->num_players);
- fprintf( OF, "\t\t<maxplayers>%d</maxplayers>\n",
- server->max_players);
-
- if ( server->type->flags & TF_RAW_STYLE_TRIBES)
- {
- fprintf( OF, "\t\t<ping>%d</ping>\n",
- server->ping_total/server->n_requests);
- fprintf( OF, "\t\t<retries>%d</retries>\n",
- server->n_retries);
- }
-
- if ( server->type->flags & TF_RAW_STYLE_QUAKE)
- {
- fprintf( OF, "\t\t<address>%s</address>\n",
- xml_escape(server->address));
- fprintf( OF, "\t\t<protocolversion>%d</protocolversion>\n",
- server->protocol_version);
- }
- }
-
- if ( ! server->type->master && server->error == NULL)
- {
- if ( get_server_rules)
- server->type->display_xml_rule_func( server);
- if ( get_player_info)
- server->type->display_xml_player_func( server);
- }
-
- fprintf( OF, "\t</server>\n");
- }
-
- void
- xml_header()
- {
- fprintf( OF, "<?xml version=\"1.0\" encoding=\"%s\"?>\n<qstat>\n",
- xml_encoding == ENCODING_LATIN_1 ? "iso-8859-1" : "UTF-8");
- }
-
- void
- xml_footer()
- {
- fprintf( OF, "</qstat>\n");
- }
-
- void
- xml_display_server_rules( struct qserver *server)
- {
- struct rule *rule;
- rule= server->rules;
-
- fprintf( OF, "\t\t<rules>\n");
- for ( ; rule != NULL; rule= rule->next)
- {
- fprintf( OF, "\t\t\t<rule name=\"%s\">%s</rule>\n",
- xml_escape(rule->name), xml_escape(rule->value));
- }
- fprintf( OF, "\t\t</rules>\n");
- }
-
- void
- xml_display_q_player_info( struct qserver *server)
- {
- struct player *player;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- fprintf( OF, "\t\t\t<player number=\"%d\">\n",
- player->number);
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<address>%s</address>\n",
- xml_escape(player->address));
- fprintf( OF, "\t\t\t\t<score>%d</score>\n",
- player->frags);
- fprintf( OF, "\t\t\t\t<time>%s</time>\n",
- xml_escape(play_time(player->connect_time,1)));
-
- if ( color_names)
- {
- fprintf( OF, "\t\t\t\t<color for=\"shirt\">%s</color>\n",
- xml_escape(quake_color(player->shirt_color)));
- fprintf( OF, "\t\t\t\t<color for=\"pants\">%s</color>\n",
- xml_escape(quake_color(player->pants_color)));
- }
- else
- {
- fprintf( OF, "\t\t\t\t<color for=\"shirt\">%d</color>\n",
- quake_color(player->shirt_color));
- fprintf( OF, "\t\t\t\t<color for=\"pants\">%d</color>\n",
- quake_color(player->pants_color));
- }
-
- fprintf( OF, "\t\t\t</player>\n");
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
- void
- xml_display_qw_player_info( struct qserver *server)
- {
- struct player *player;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- fprintf( OF, "\t\t\t<player number=\"%d\">\n",
- player->number);
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<score>%d</score>\n",
- player->frags);
- fprintf( OF, "\t\t\t\t<time>%s</time>\n",
- xml_escape(play_time(player->connect_time,1)));
-
- if ( color_names)
- {
- fprintf( OF, "\t\t\t\t<color for=\"shirt\">%s</color>\n",
- xml_escape(quake_color(player->shirt_color)));
- fprintf( OF, "\t\t\t\t<color for=\"pants\">%s</color>\n",
- xml_escape(quake_color(player->pants_color)));
- }
- else
- {
- fprintf( OF, "\t\t\t\t<color for=\"shirt\">%d</color>\n",
- quake_color(player->shirt_color));
- fprintf( OF, "\t\t\t\t<color for=\"pants\">%d</color>\n",
- quake_color(player->pants_color));
- }
-
- fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
- player->ping);
- fprintf( OF, "\t\t\t\t<skin>%s</skin>\n",
- player->skin ? xml_escape(player->skin) : "");
-
- fprintf( OF, "\t\t\t</player>\n");
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
- void
- xml_display_q2_player_info( struct qserver *server)
- {
- struct player *player;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- fprintf( OF, "\t\t\t<player>\n");
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<score>%d</score>\n", player->frags);
- if ( server->flags & FLAG_PLAYER_TEAMS)
- fprintf( OF, "\t\t\t\t<team>%d</team>\n", player->team);
- fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
- player->ping);
-
- fprintf( OF, "\t\t\t</player>\n");
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
- void
- xml_display_unreal_player_info( struct qserver *server)
- {
- struct player *player;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- fprintf( OF, "\t\t\t<player>\n");
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<score>%d</score>\n",
- player->frags);
- fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
- player->ping);
- fprintf( OF, "\t\t\t\t<team>%d</team>\n",
- player->team);
- fprintf( OF, "\t\t\t\t<skin>%s</skin>\n",
- player->skin ? xml_escape(player->skin) : "");
- fprintf( OF, "\t\t\t\t<mesh>%s</mesh>\n",
- player->mesh ? xml_escape(player->mesh) : "");
- fprintf( OF, "\t\t\t\t<face>%s</face>\n",
- player->face ? xml_escape(player->face) : "");
-
- fprintf( OF, "\t\t\t</player>\n");
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
- void
- xml_display_halflife_player_info( struct qserver *server)
- {
- struct player *player;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- fprintf( OF, "\t\t\t<player>\n");
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<score>%d</score>\n",
- player->frags);
- fprintf( OF, "\t\t\t\t<time>%s</time>\n",
- xml_escape(play_time( player->connect_time,1)));
-
- fprintf( OF, "\t\t\t</player>\n");
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
- void
- xml_display_tribes_player_info( struct qserver *server)
- {
- struct player *player;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- fprintf( OF, "\t\t\t<player>\n");
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<score>%d</score>\n",
- player->frags);
- fprintf( OF, "\t\t\t\t<team>%d</team>\n",
- player->team);
- fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
- player->ping);
- fprintf( OF, "\t\t\t\t<packetloss>%d</packetloss>\n",
- player->packet_loss);
-
- fprintf( OF, "\t\t\t</player>\n");
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
- void
- xml_display_tribes2_player_info( struct qserver *server)
- {
- static char fmt[]= "%s" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
- struct player *player;
- char *type;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- if ( player->team_name)
- {
- switch( player->type_flag)
- {
- case PLAYER_TYPE_BOT:
- type= "Bot";
- break;
- case PLAYER_TYPE_ALIAS:
- type= "Alias";
- break;
- default:
- type= "";
- break;
- }
-
- fprintf( OF, "\t\t\t<player>\n");
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<score>%d</score>\n",
- player->frags);
- fprintf( OF, "\t\t\t\t<team number=\"%d\">%s</team>\n",
- player->team, xml_escape(player->team_name));
- fprintf( OF, "\t\t\t\t<type>%s</type>\n",
- xml_escape(type));
- fprintf( OF, "\t\t\t\t<clan>%s</clan>\n",
- player->tribe_tag ? xml_escape(xform_name(player->tribe_tag,server)) : "");
-
- fprintf( OF, "\t\t\t</player>\n");
- }
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
- void
- xml_display_bfris_player_info( struct qserver *server)
- {
- struct player *player;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- fprintf( OF, "\t\t\t<player number=\"%d\">\n",
- player->number);
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<score type=\"score\">%d</score>\n",
- player->score);
- fprintf( OF, "\t\t\t\t<score type=\"frags\">%d</score>\n",
- player->frags);
- fprintf( OF, "\t\t\t\t<team>%s</team>\n",
- xml_escape(player->team_name));
- fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
- player->ping);
- fprintf( OF, "\t\t\t\t<ship>%d</ship>\n",
- player->ship);
-
- fprintf( OF, "\t\t\t</player>\n");
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
- void
- xml_display_descent3_player_info( struct qserver *server)
- {
- struct player *player;
-
- fprintf( OF, "\t\t<players>\n");
-
- player= server->players;
- for ( ; player != NULL; player= player->next)
- {
- fprintf( OF, "\t\t\t<player>\n");
-
- fprintf( OF, "\t\t\t\t<name>%s</name>\n",
- xml_escape(xform_name( player->name, server)));
- fprintf( OF, "\t\t\t\t<score>%d</score>\n",
- player->frags);
- fprintf( OF, "\t\t\t\t<deaths>%d</deaths>\n",
- player->deaths);
- fprintf( OF, "\t\t\t\t<ping>%d</ping>\n",
- player->ping);
- fprintf( OF, "\t\t\t\t<team>%d</team>\n",
- player->team);
-
- fprintf( OF, "\t\t\t</player>\n");
- }
-
- fprintf( OF, "\t\t</players>\n");
- }
-
-
- void
- display_progress()
- {
- fprintf( stderr, "\r%d/%d (%d timed out, %d down)",
- num_servers_returned+num_servers_timed_out,
- num_servers_total,
- num_servers_timed_out,
- num_servers_down);
- }
-
- /* ----- END MODIFICATION ----- Don't need to change anything below here. */
-
-
- void set_non_blocking( int fd);
- int set_fds( fd_set *fds);
- void get_next_timeout( struct timeval *timeout);
-
- void set_file_descriptors();
- int wait_for_file_descriptors( struct timeval *timeout);
- struct qserver * get_next_ready_server();
-
-
- /* Misc flags
- */
-
- char * NO_SERVER_RULES= NULL;
- int NO_PLAYER_INFO= 0xffff;
- struct timeval packet_recv_time;
- int one_server_type_id= ~ MASTER_SERVER;
- static int one= 1;
- static int little_endian;
- static int big_endian;
- unsigned int swap_long( void *);
- unsigned short swap_short( void *);
- unsigned int swap_long_from_little( void *l);
- unsigned short swap_short_from_little( void *l);
- char * strndup( char *string, int len);
- #define FORCE 1
-
- /* Print an error message and the program usage notes
- */
-
- void
- usage( char *msg, char **argv, char *a1)
- {
- server_type *type;
-
- if ( msg)
- fprintf( stderr, msg, a1);
-
- printf( "Usage: %s [options ...]\n", argv[0]);
- printf( "\t[-default server-type] [-f file] [host[:port]] ...\n");
- printf( "Where host is an IP address or host name\n");
- type= &types[0];
- for ( ; type->id != Q_UNKNOWN_TYPE; type++)
- printf( "%s\t\tquery %s server\n", type->type_option,
- type->game_name);
- printf( "-default\tset default server type:");
- type= &types[0];
- for ( ; type->id != Q_UNKNOWN_TYPE; type++)
- printf( " %s", type->type_string);
- puts("");
- printf( "-f\t\tread hosts from file\n");
- printf( "-R\t\tfetch and display server rules\n");
- printf( "-P\t\tfetch and display player info\n");
- printf( "-sort\t\tsort servers and/or players\n");
- printf( "-u\t\tonly display servers that are up\n");
- printf( "-nf\t\tdo not display full servers\n");
- printf( "-ne\t\tdo not display empty servers\n");
- printf( "-cn\t\tdisplay color names instead of numbers\n");
- printf( "-ncn\t\tdisplay color numbers instead of names\n");
- printf( "-hc\t\tdisplay colors in #rrggbb format\n");
- printf( "-tc\t\tdisplay time in clock format (DhDDmDDs)\n");
- printf( "-tsw\t\tdisplay time in stop-watch format (DD:DD:DD)\n");
- printf( "-ts\t\tdisplay time in seconds\n");
- printf( "-pa\t\tdisplay player address\n");
- printf( "-hpn\t\tdisplay player names in hex\n");
- printf( "-nh\t\tdo not display header\n");
- printf( "-old\t\told style display\n");
- printf( "-progress\tdisplay progress meter (text only)\n");
- printf( "-retry\t\tnumber of retries, default is %d\n", DEFAULT_RETRIES);
- printf( "-interval\tinterval between retries, default is %.2lf seconds\n",
- DEFAULT_RETRY_INTERVAL / 1000.0);
- printf( "-mi\t\tinterval between master server retries, default is %.2lf seconds\n",
- (DEFAULT_RETRY_INTERVAL*4) / 1000.0);
- printf( "-timeout\ttotal time in seconds before giving up\n");
- printf( "-maxsim\t\tset maximum simultaneous queries\n");
- printf( "-errors\t\tdisplay errors\n");
- printf( "-of\t\toutput file\n");
- printf( "-raw <delim>\toutput in raw format using <delim> as delimiter\n");
- printf( "-xml\t\toutput status data as an XML document\n");
- printf( "-Th,-Ts,-Tp,-Tr,-Tt\toutput templates: header, server, player, rule, and trailer\n");
- printf( "-srcport <range>\tSend packets from these network ports\n");
- printf( "-srcip <IP>\tSend packets using this IP address\n");
- printf( "-H\t\tresolve host names\n");
- printf( "-Hcache\t\thost name cache file\n");
- printf( "\n");
- printf( "Sort keys:\n");
- printf( " servers: p=by-ping, g=by-game, i=by-IP-address, h=by-hostname, n=by-#-players, l=by-list-order\n");
- printf( " players: P=by-ping, F=by-frags, T=by-team\n");
- printf( "\nqstat version %s\n", VERSION);
- exit(0);
- }
-
- struct server_arg {
- int type_id;
- server_type *type;
- char *arg;
- char *outfilename;
- char *query_arg;
- };
-
- server_type*
- find_server_type_id( int type_id)
- {
- server_type *type= &types[0];
- for ( ; type->id != Q_UNKNOWN_TYPE; type++)
- if ( type->id == type_id)
- return type;
- return NULL;
- }
-
- server_type*
- find_server_type_string( char* type_string)
- {
- server_type *type= &types[0];
- char *t= type_string;
- while ( *t) *t++= tolower( *t);
-
- for ( ; type->id != Q_UNKNOWN_TYPE; type++)
- if ( strcmp( type->type_string, type_string) == 0)
- return type;
- return NULL;
- }
-
- server_type*
- find_server_type_option( char* option)
- {
- server_type *type= &types[0];
- for ( ; type->id != Q_UNKNOWN_TYPE; type++)
- if ( strcmp( type->type_option, option) == 0)
- return type;
- return NULL;
- }
-
- server_type*
- parse_server_type_option( char* option, int *outfile, char **query_arg)
- {
- server_type *type= &types[0];
- char *comma, *arg;
- int len;
-
- *outfile= 0;
- *query_arg= 0;
-
- comma= strchr( option, ',');
- if ( comma)
- *comma++= '\0';
-
- for ( ; type->id != Q_UNKNOWN_TYPE; type++)
- if ( strcmp( type->type_option, option) == 0)
- break;
-
- if ( type->id == Q_UNKNOWN_TYPE)
- return NULL;
-
- if ( ! comma)
- return type;
-
- if ( strcmp( comma, "outfile") == 0) {
- *outfile= 1;
- comma= strchr( comma, ',');
- if ( ! comma)
- return type;
- *comma++= '\0';
- }
-
- *query_arg= comma;
- arg= *query_arg;
- do {
- comma= strchr( arg, ',');
- if (comma)
- len= comma-arg;
- else
- len= strlen( arg);
- if ( strncmp( arg, "outfile", len) == 0)
- *outfile= 1;
- arg= comma+1;
- } while ( comma);
- return type;
- }
-
- void
- add_server_arg( char *arg, int type, char *outfilename, char *query_arg,
- struct server_arg **args, int *n, int *max)
- {
- if ( *n == *max) {
- if ( *max == 0) {
- *max= 4;
- *args= (struct server_arg*)malloc(sizeof(struct server_arg) * (*max));
- }
- else {
- (*max)*= 2;
- *args= (struct server_arg*) realloc( *args,
- sizeof(struct server_arg) * (*max));
- }
- }
- (*args)[*n].type_id= type;
- /* (*args)[*n].type= find_server_type_id( type); */
- (*args)[*n].type= NULL;
- (*args)[*n].arg= arg;
- (*args)[*n].outfilename= outfilename;
- (*args)[*n].query_arg= query_arg;
- (*n)++;
- }
-
-
- void
- add_query_param( struct qserver *server, char *arg)
- {
- char *equal;
- struct query_param *param;
-
- equal= strchr( arg, '=');
- *equal++= '\0';
-
- param= (struct query_param *) malloc( sizeof(struct query_param));
- param->key= arg;
- param->value= equal;
- sscanf( equal, "%i", ¶m->i_value);
- sscanf( equal, "%i", ¶m->ui_value);
- param->next= server->params;
- server->params= param;
- }
-
- char *
- get_param_value( struct qserver *server, char *key, char *default_value)
- {
- struct query_param *p= server->params;
- for ( ; p; p= p->next)
- if ( strcasecmp( key, p->key) == 0)
- return p->value;
- return default_value;
- }
-
- int
- get_param_i_value( struct qserver *server, char *key, int default_value)
- {
- struct query_param *p= server->params;
- for ( ; p; p= p->next)
- if ( strcasecmp( key, p->key) == 0)
- return p->i_value;
- return default_value;
- }
-
- unsigned int
- get_param_ui_value( struct qserver *server, char *key,
- unsigned int default_value)
- {
- struct query_param *p= server->params;
- for ( ; p; p= p->next)
- if ( strcasecmp( key, p->key) == 0)
- return p->ui_value;
- return default_value;
- }
-
- int
- parse_source_address( char *addr, unsigned int *ip, unsigned short *port)
- {
- char *colon;
- colon= strchr( addr, ':');
- if ( colon) {
- *colon= '\0';
- *port= atoi( colon+1);
- if ( colon == addr)
- return 0;
- }
- else
- *port= 0;
-
- *ip= inet_addr( addr);
- if ( *ip == INADDR_NONE && !isdigit( *ip))
- *ip= hcache_lookup_hostname( addr);
- if ( *ip == INADDR_NONE) {
- fprintf( stderr, "%s: Not an IP address or unknown host name\n", addr);
- return -1;
- }
- *ip= ntohl( *ip);
- return 0;
- }
-
- int
- parse_source_port( char *port, unsigned short *low, unsigned short *high)
- {
- char *dash;
- *low= atoi( port);
- dash= strchr( port, '-');
- *high= 0;
- if ( dash)
- *high= atoi( dash+1);
- if ( *high == 0)
- *high= *low;
-
- if ( *high < *low) {
- fprintf( stderr, "%s: Invalid port range\n", port);
- return -1;
- }
- return 0;
- }
-
- void
- add_config_server_types()
- {
- int n_config_types, n_builtin_types, i;
- server_type **config_types;
- server_type *new_types, *type;
- config_types= qsc_get_config_server_types( &n_config_types);
-
- if ( n_config_types == 0)
- return;
-
- n_builtin_types= (sizeof( builtin_types) / sizeof(server_type)) - 1;
- new_types= (server_type*) malloc( sizeof(server_type) * (n_builtin_types +
- n_config_types + 1));
-
- memcpy( new_types, &builtin_types[0], n_builtin_types*sizeof(server_type));
- type= &new_types[n_builtin_types];
- for ( i= n_config_types; i; i--, config_types++, type++)
- *type= **config_types;
- n_server_types= n_builtin_types + n_config_types;
- new_types[n_server_types].id= Q_UNKNOWN_TYPE;
- if ( types != &builtin_types[0])
- free( types);
- types= new_types;
- }
-
- void
- revert_server_types()
- {
- if ( types != &builtin_types[0])
- free( types);
- n_server_types= (sizeof( builtin_types) / sizeof(server_type)) - 1;
- types= &builtin_types[0];
- }
-
-
- main( int argc, char *argv[])
- {
- int pktlen, rc, fd;
- long pkt_data[PACKET_LEN/sizeof(long)];
- char *pkt= (char*)&pkt_data[0];
- struct timeval timeout;
- int arg, n_files, i;
- struct qserver *server;
- char **files, *outfilename, *query_arg;
- struct server_arg *server_args= NULL;
- int n_server_args= 0, max_server_args= 0;
- int show_recv_packets= 0;
- int bind_retry= 0;
- int default_server_type_id;
-
- #ifdef _WIN32
- WORD version= MAKEWORD(1,1);
- WSADATA wsa_data;
- if ( WSAStartup(version,&wsa_data) != 0) {
- fprintf( stderr, "Could not open winsock\n");
- exit(1);
- }
- #endif
-
- types= &builtin_types[0];
- n_server_types= (sizeof( builtin_types) / sizeof(server_type)) - 1;
-
- i= qsc_load_default_config_files();
- if ( i == -1)
- return 1;
- else if ( i == 0)
- add_config_server_types();
-
- if ( argc == 1)
- usage(NULL,argv,NULL);
-
- OF= stdout;
-
- files= (char **) malloc( sizeof(char*) * (argc/2));
- n_files= 0;
-
- default_server_type_id= Q_SERVER;
- little_endian= ((char*)&one)[0];
- big_endian= !little_endian;
-
- for ( arg= 1; arg < argc; arg++) {
- if ( argv[arg][0] != '-')
- break;
- outfilename= NULL;
- if ( strcmp( argv[arg], "-nocfg") == 0 && arg == 1) {
- revert_server_types();
- }
- else if ( strcmp( argv[arg], "-f") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -f\n", argv,NULL);
- files[n_files++]= argv[arg];
- }
- else if ( strcmp( argv[arg], "-retry") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -retry\n", argv,NULL);
- n_retries= atoi( argv[arg]);
- if ( n_retries <= 0) {
- fprintf( stderr, "retries must be greater than zero\n");
- exit(1);
- }
- }
- else if ( strcmp( argv[arg], "-interval") == 0) {
- double value= 0.0;
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -interval\n", argv,NULL);
- sscanf( argv[arg], "%lf", &value);
- if ( value < 0.1) {
- fprintf( stderr, "retry interval must be greater than 0.1\n");
- exit(1);
- }
- retry_interval= (int)(value * 1000);
- }
- else if ( strcmp( argv[arg], "-mi") == 0) {
- double value= 0.0;
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -mi\n", argv,NULL);
- sscanf( argv[arg], "%lf", &value);
- if ( value < 0.1) {
- fprintf( stderr, "interval must be greater than 0.1\n");
- exit(1);
- }
- master_retry_interval= (int)(value * 1000);
- }
- else if ( strcmp( argv[arg], "-H") == 0)
- hostname_lookup= 1;
- else if ( strcmp( argv[arg], "-u") == 0)
- up_servers_only= 1;
- else if ( strcmp( argv[arg], "-nf") == 0)
- no_full_servers= 1;
- else if ( strcmp( argv[arg], "-ne") == 0)
- no_empty_servers= 1;
- else if ( strcmp( argv[arg], "-nh") == 0)
- no_header_display= 1;
- else if ( strcmp( argv[arg], "-old") == 0)
- new_style= 0;
- else if ( strcmp( argv[arg], "-P") == 0)
- get_player_info= 1;
- else if ( strcmp( argv[arg], "-R") == 0)
- get_server_rules= 1;
- else if ( strncmp( argv[arg], "-raw", 4) == 0) {
- if ( argv[arg][4] == ',') {
- if ( strcmp( &argv[arg][5], "game") == 0)
- show_game_in_raw= 1;
- else
- usage( "Unknown -raw option\n", argv, NULL);
- }
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -raw\n", argv,NULL);
- raw_delimiter= argv[arg];
- raw_display= 1;
- }
- else if ( strcmp( argv[arg], "-xml") == 0) {
- xml_display= 1;
- if (raw_display == 1)
- usage( "cannot specify both -raw and -xml\n", argv,NULL);
- }
- else if ( strcmp( argv[arg], "-utf8") == 0) {
- xml_encoding= ENCODING_UTF_8;
- }
- else if ( strcmp( argv[arg], "-ncn") == 0) {
- color_names= 0;
- }
- else if ( strcmp( argv[arg], "-cn") == 0) {
- color_names= 1;
- }
- else if ( strcmp( argv[arg], "-hc") == 0) {
- color_names= 2;
- }
- else if ( strcmp( argv[arg], "-tc") == 0) {
- time_format= CLOCK_TIME;
- }
- else if ( strcmp( argv[arg], "-tsw") == 0) {
- time_format= STOPWATCH_TIME;
- }
- else if ( strcmp( argv[arg], "-ts") == 0) {
- time_format= SECONDS;
- }
- else if ( strcmp( argv[arg], "-pa") == 0) {
- player_address= 1;
- }
- else if ( strcmp( argv[arg], "-hpn") == 0) {
- hex_player_names= 1;
- }
- else if ( strncmp( argv[arg], "-maxsimultaneous", 7) == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -maxsimultaneous\n", argv,NULL);
- max_simultaneous= atoi(argv[arg]);
- if ( max_simultaneous <= 0)
- usage( "value for -maxsimultaneous must be > 0\n", argv,NULL);
- if ( max_simultaneous > FD_SETSIZE)
- max_simultaneous= FD_SETSIZE;
- }
- else if ( strcmp( argv[arg], "-raw-arg") == 0) {
- raw_arg= 1000;
- }
- else if ( strcmp( argv[arg], "-timeout") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -timeout\n", argv,NULL);
- run_timeout= atoi( argv[arg]);
- if ( run_timeout <= 0)
- usage( "value for -timeout must be > 0\n", argv,NULL);
- }
- else if ( strcmp( argv[arg], "-progress") == 0) {
- progress= 1;
- }
- else if ( strcmp( argv[arg], "-Hcache") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -Hcache\n", argv,NULL);
- if ( hcache_open( argv[arg], 0) == -1)
- return 1;
- }
- else if ( strcmp( argv[arg], "-default") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -default\n", argv,NULL);
- default_server_type= find_server_type_string( argv[arg]);
- if ( default_server_type == NULL) {
- char opt[256], *o= &opt[0];
- sprintf( opt, "-%s", argv[arg]);
- while ( *o) *o++= tolower(*o);
- default_server_type= find_server_type_option( opt);
- }
- if ( default_server_type == NULL) {
- fprintf( stderr, "unknown server type \"%s\"\n", argv[arg]);
- usage( NULL, argv,NULL);
- }
- default_server_type_id= default_server_type->id;
- default_server_type= NULL;
- }
- else if ( strncmp( argv[arg], "-Tserver", 3) == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- if ( read_qserver_template( argv[arg]) == -1)
- return 1;
- }
- else if ( strncmp( argv[arg], "-Trule", 3) == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- if ( read_rule_template( argv[arg]) == -1)
- return 1;
- }
- else if ( strncmp( argv[arg], "-Theader", 3) == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- if ( read_header_template( argv[arg]) == -1)
- return 1;
- }
- else if ( strncmp( argv[arg], "-Ttrailer", 3) == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- if ( read_trailer_template( argv[arg]) == -1)
- return 1;
- }
- else if ( strncmp( argv[arg], "-Tplayer", 3) == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- if ( read_player_template( argv[arg]) == -1)
- return 1;
- }
- else if ( strcmp( argv[arg], "-sort") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for -sort\n", argv, NULL);
- strncpy( sort_keys, argv[arg], sizeof(sort_keys)-1);
- rc= strspn( sort_keys, SUPPORTED_SORT_KEYS);
- if ( rc != strlen( sort_keys)) {
- fprintf( stderr, "Unknown sort key \"%c\", valid keys are \"%s\"\n",
- sort_keys[rc], SUPPORTED_SORT_KEYS);
- return 1;
- }
- server_sort= strpbrk( sort_keys, SUPPORTED_SERVER_SORT) != NULL;
- if ( strchr( sort_keys, 'l'))
- server_sort= 1;
- player_sort= strpbrk( sort_keys, SUPPORTED_PLAYER_SORT) != NULL;
- }
- else if ( strcmp( argv[arg], "-errors") == 0) {
- show_errors++;
- }
- else if ( strcmp( argv[arg], "-of") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- OF= fopen( argv[arg], "w");
- if ( OF == NULL) {
- perror( argv[arg]);
- return 1;
- }
- }
- else if ( strcmp( argv[arg], "-af") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- OF= fopen( argv[arg], "a");
- if ( OF == NULL) {
- perror( argv[arg]);
- return 1;
- }
- }
- else if ( strcmp( argv[arg], "-htmlnames") == 0) {
- html_names= 1;
- }
- else if ( strcmp( argv[arg], "-nohtmlnames") == 0) {
- html_names= 0;
- }
- else if ( strcmp( argv[arg], "-htmlmode") == 0) {
- html_mode= 1;
- }
- else if ( strcmp( argv[arg], "-carets") == 0) {
- strip_carets= 0;
- }
- else if ( strcmp( argv[arg], "-d") == 0) {
- show_recv_packets= 1;
- }
- else if ( strcmp( argv[arg], "-srcip") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- if ( parse_source_address( argv[arg], &source_ip, &source_port) == -1)
- return 1;
- if ( source_port) {
- source_port_low= source_port;
- source_port_high= source_port;
- }
- }
- else if ( strcmp( argv[arg], "-srcport") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- if ( parse_source_port( argv[arg], &source_port_low, &source_port_high) == -1)
- return 1;
- source_port= source_port_low;
- }
- else if ( strcmp( argv[arg], "-cfg") == 0) {
- arg++;
- if ( arg >= argc)
- usage( "missing argument for %s\n", argv, argv[arg-1]);
- if ( qsc_load_config_file( argv[arg]) == -1)
- return 1;
- add_config_server_types();
- }
- #ifdef _WIN32
- else if ( strcmp( argv[arg], "-noconsole") == 0) {
- FreeConsole();
- }
- #endif
- else {
- int outfile;
- server_type *type;
- arg++;
- if ( arg >= argc) {
- fprintf( stderr, "missing argument for \"%s\"\n", argv[arg-1]);
- return 1;
- }
- type= parse_server_type_option( argv[arg-1], &outfile, &query_arg);
- if ( type == NULL) {
- fprintf( stderr, "unknown option \"%s\"\n", argv[arg-1]);
- return 1;
- }
- outfilename= NULL;
- if ( outfile) {
- outfilename= strchr( argv[arg], ',');
- if ( outfilename == NULL) {
- fprintf( stderr, "missing file name for \"%s,outfile\"\n",
- argv[arg-1]);
- return 1;
- }
- *outfilename++= '\0';
- }
- if ( query_arg && !(type->flags & TF_QUERY_ARG)) {
- fprintf( stderr, "option flag \"%s\" not allowed for this server type\n",
- query_arg);
- return 1;
- }
- if ( type->flags & TF_QUERY_ARG_REQUIRED && !query_arg) {
- fprintf( stderr, "option flag missing for server type \"%s\"\n",
- argv[arg-1]);
- return 1;
- }
- add_server_arg( argv[arg], type->id, outfilename, query_arg,
- &server_args, &n_server_args, &max_server_args);
- }
- }
-
- start_time= time(0);
-
- default_server_type= find_server_type_id( default_server_type_id);
-
- for ( i= 0; i < n_files; i++)
- add_file( files[i]);
-
- for ( ; arg < argc; arg++)
- add_qserver( argv[arg], default_server_type, NULL, NULL);
-
- for ( i= 0; i < n_server_args; i++) {
- server_type *server_type= find_server_type_id( server_args[i].type_id);
- add_qserver( server_args[i].arg, server_type,
- server_args[i].outfilename, server_args[i].query_arg);
- }
-
- free( server_args);
-
- if ( servers == NULL)
- exit(1);
-
- max_connmap= max_simultaneous + 10;
- connmap= (struct qserver**) calloc( 1, sizeof(struct qserver*) * max_connmap);
-
- if ( color_names == -1)
- color_names= ( raw_display) ? DEFAULT_COLOR_NAMES_RAW :
- DEFAULT_COLOR_NAMES_DISPLAY;
-
- if ( time_format == -1)
- time_format= ( raw_display) ? DEFAULT_TIME_FMT_RAW :
- DEFAULT_TIME_FMT_DISPLAY;
-
- if ( (one_server_type_id & MASTER_SERVER) || one_server_type_id == 0)
- display_prefix= 1;
-
- if ( xml_display)
- xml_header();
- else if ( new_style && ! raw_display && ! have_server_template())
- display_header();
- else if ( have_header_template())
- template_display_header();
-
- q_serverinfo.length= htons( q_serverinfo.length);
- h2_serverinfo.length= htons( h2_serverinfo.length);
- q_player.length= htons( q_player.length);
-
- bind_sockets();
-
- while ( connected || (!connected && bind_retry==-2)) {
- int last_connected= connected;
-
- if ( ! connected && bind_retry==-2) {
- rc= wait_for_timeout( 60);
- bind_retry= bind_sockets();
- continue;
- }
- bind_retry= 0;
-
- set_file_descriptors();
-
- if ( progress)
- display_progress();
- get_next_timeout( &timeout);
-
- rc= wait_for_file_descriptors( &timeout);
-
- if ( rc == 0) {
- if ( run_timeout && time(0)-start_time >= run_timeout)
- break;
- send_packets();
- bind_retry= bind_sockets();
- continue;
- }
- if ( rc == SOCKET_ERROR) {
- perror("select");
- break;
- }
-
- gettimeofday( &packet_recv_time, NULL);
- fd= 0;
- for ( ; rc; rc--) {
- struct sockaddr_in addr;
- int addrlen= sizeof(addr);
- server= get_next_ready_server();
- if ( server == NULL)
- break;
- if ( server->flags & FLAG_BROADCAST)
- pktlen= recvfrom( server->fd, pkt, sizeof(pkt_data), 0,
- (struct sockaddr*)&addr, &addrlen);
- else
- pktlen= recv( server->fd, pkt, sizeof(pkt_data), 0);
-
- if ( pktlen == SOCKET_ERROR) {
- if ( connection_refused()) {
- server->server_name= DOWN;
- num_servers_down++;
- cleanup_qserver( server, 1);
- if ( ! connected)
- bind_retry= bind_sockets();
- }
- continue;
- }
- if ( server->flags & FLAG_BROADCAST) {
- struct qserver *broadcast= server;
- /* create new server and init */
- server= add_qserver_byaddr( ntohl(addr.sin_addr.s_addr),
- ntohs(addr.sin_port), server->type, NULL);
- if ( server == NULL) {
- if ( show_errors) {
- fprintf(stderr,
- "duplicate or invalid packet received from 0x%08x:%hu",
- ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
- print_packet( NULL, pkt, pktlen);
- }
- continue;
- }
- server->packet_time1= broadcast->packet_time1;
- server->packet_time2= broadcast->packet_time2;
- server->ping_total= broadcast->ping_total;
- server->n_requests= broadcast->n_requests;
- server->n_packets= broadcast->n_packets;
- broadcast->n_servers++;
- }
-
- if ( show_recv_packets)
- print_packet( server, pkt, pktlen);
- server->type->packet_func( server, pkt, pktlen);
- }
-
- if ( run_timeout && time(0)-start_time >= run_timeout)
- break;
- if ( connected != last_connected)
- bind_retry= bind_sockets();
- }
-
- finish_output();
-
- return 0;
- }
-
- void
- finish_output()
- {
- int i;
- hcache_update_file();
-
- if ( progress) {
- display_progress();
- fputs( "\n", stderr);
- }
-
- if ( server_sort) {
- struct qserver **array, *server;
- if ( strchr( sort_keys, 'l') &&
- strpbrk( sort_keys, SUPPORTED_SERVER_SORT) == NULL) {
- server= servers;
- for ( ; server; server= server->next)
- display_server( server);
- }
- else {
- array= (struct qserver **) malloc( sizeof(struct qserver *) *
- num_servers_total);
- server= servers;
- for ( i= 0; server != NULL; i++) {
- array[i]= server;
- server= server->next;
- }
- sort_servers( array, num_servers_total);
- if ( progress)
- fprintf( stderr, "\n");
- for ( i= 0; i < num_servers_total; i++)
- display_server( array[i]);
- free( array);
- }
- }
- else {
- struct qserver *server;
- server= servers;
- for ( ; server; server= server->next)
- if ( server->server_name == HOSTNOTFOUND)
- display_server( server);
- }
-
- if ( xml_display)
- xml_footer();
- else if ( have_trailer_template())
- template_display_trailer();
-
- if ( OF != stdout)
- fclose( OF);
- }
-
-
- void
- add_file( char *filename)
- {
- FILE *file;
- char name[200], *comma, *query_arg;
- server_type* type;
-
- if ( strcmp( filename, "-") == 0) {
- file= stdin;
- current_filename= NULL;
- }
- else {
- file= fopen( filename, "r");
- current_filename= filename;
- }
- current_fileline= 1;
-
- if ( file == NULL) {
- perror( filename);
- return;
- }
- for ( ; fscanf( file, "%s", name) == 1; current_fileline++) {
- comma= strchr( name, ',');
- if ( comma) {
- *comma++= '\0';
- query_arg= strdup( comma);
- }
- type= find_server_type_string( name);
- if ( type == NULL)
- add_qserver( name, default_server_type, NULL, NULL);
- else if ( fscanf( file, "%s", name) == 1) {
- if ( type->flags & TF_QUERY_ARG && comma && *query_arg)
- add_qserver( name, type, NULL, query_arg);
- else
- add_qserver( name, type, NULL, NULL);
- }
- }
-
- if ( file != stdin)
- fclose(file);
-
- current_fileline= 0;
- }
-
- void
- print_file_location()
- {
- if ( current_fileline != 0)
- fprintf( stderr, "%s:%d: ", current_filename?current_filename:"<stdin>",
- current_fileline);
- }
-
- void
- parse_query_params( struct qserver *server, char *params)
- {
- char *comma, *arg= params;
- do {
- comma= strchr(arg,',');
- if ( comma)
- *comma= '\0';
- if ( strchr( arg, '='))
- add_query_param( server, arg);
- arg= comma+1;
- } while ( comma);
- }
-
- int
- add_qserver( char *arg, server_type* type, char *outfilename, char *query_arg)
- {
- struct qserver *server;
- int flags= 0;
- char *colon= NULL, *arg_copy, *hostname= NULL;
- unsigned int ipaddr;
- unsigned short port;
-
- if ( run_timeout && time(0)-start_time >= run_timeout) {
- finish_output();
- exit(0);
- }
-
- port= type->default_port;
-
- if ( outfilename && strcmp( outfilename, "-") != 0) {
- FILE *outfile= fopen( outfilename, "r+");
- if ( outfile == NULL && (errno == EACCES || errno == EISDIR ||
- errno == ENOSPC || errno == ENOTDIR)) {
- perror( outfilename);
- return -1;
- }
- if ( outfile)
- fclose(outfile);
- }
-
- arg_copy= strdup(arg);
-
- colon= strchr( arg, ':');
- if ( colon != NULL) {
- sscanf( colon+1, "%hd", &port);
- *colon= '\0';
- }
-
- if ( *arg == '+') {
- flags|= FLAG_BROADCAST;
- arg++;
- }
-
- ipaddr= inet_addr(arg);
- if ( ipaddr == INADDR_NONE) {
- if ( strcmp( arg, "255.255.255.255") != 0)
- ipaddr= htonl( hcache_lookup_hostname(arg));
- }
- else if ( hostname_lookup && !(flags&FLAG_BROADCAST))
- hostname= hcache_lookup_ipaddr( ntohl(ipaddr));
-
- if ( ipaddr == INADDR_NONE && strcmp( arg, "255.255.255.255") != 0) {
- print_file_location();
- fprintf( stderr, "%s: %s\n", arg, strherror(h_errno));
- server= (struct qserver *) calloc( 1, sizeof( struct qserver));
- init_qserver( server);
- server->arg= arg_copy;
- server->server_name= HOSTNOTFOUND;
- server->error= strdup( strherror(h_errno));
- server->port= port;
- server->type= type;
- *last_server= server;
- last_server= & server->next;
- if ( one_server_type_id == ~MASTER_SERVER)
- one_server_type_id= type->id;
- else if ( one_server_type_id != type->id)
- one_server_type_id= 0;
- return -1;
- }
-
- if ( find_server_by_address( ipaddr, port) != NULL)
- return 0;
-
- server= (struct qserver *) calloc( 1, sizeof( struct qserver));
- server->arg= arg_copy;
- if ( hostname && colon) {
- server->host_name= (char*)malloc( strlen(hostname) + strlen(colon+1)+2);
- sprintf( server->host_name, "%s:%s", hostname, colon+1);
- }
- else
- server->host_name= strdup((hostname)?hostname:arg);
-
- server->ipaddr= ipaddr;
- server->port= port;
- server->type= type;
- server->outfilename= outfilename;
- server->query_arg= query_arg;
- server->flags= flags;
- if ( query_arg)
- parse_query_params( server, query_arg);
- init_qserver( server);
-
- if ( server->type->master)
- waiting_for_masters++;
-
- if ( num_servers_total % 10 == 0)
- hcache_update_file();
-
- *last_server= server;
- last_server= & server->next;
-
- add_server_to_hash( server);
-
- if ( one_server_type_id == ~MASTER_SERVER)
- one_server_type_id= type->id;
- else if ( one_server_type_id != type->id)
- one_server_type_id= 0;
-
- return 0;
- }
-
- struct qserver *
- add_qserver_byaddr( unsigned int ipaddr, unsigned short port,
- server_type* type, int *new_server)
- {
- char arg[36];
- struct qserver *server;
- char *hostname= NULL;
-
- if ( run_timeout && time(0)-start_time >= run_timeout) {
- finish_output();
- exit(0);
- }
-
- if ( new_server)
- *new_server= 0;
- ipaddr= htonl(ipaddr);
- if ( find_server_by_address( ipaddr, port) != NULL)
- return 0;
-
- if ( new_server)
- *new_server= 1;
-
- server= (struct qserver *) calloc( 1, sizeof( struct qserver));
- server->ipaddr= ipaddr;
- ipaddr= ntohl(ipaddr);
- sprintf( arg, "%d.%d.%d.%d:%hu", ipaddr>>24, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff, port);
- server->arg= strdup(arg);
-
- if ( hostname_lookup)
- hostname= hcache_lookup_ipaddr( ipaddr);
- if ( hostname) {
- server->host_name= (char*)malloc( strlen(hostname) + 6 + 2);
- sprintf( server->host_name, "%s:%hu", hostname, port);
- }
- else
- server->host_name= strdup( arg);
-
- server->port= port;
- server->type= type;
- init_qserver( server);
-
- if ( num_servers_total % 10 == 0)
- hcache_update_file();
-
- *last_server= server;
- last_server= & server->next;
-
- add_server_to_hash( server);
-
- return server;
- }
-
- void
- add_servers_from_masters()
- {
- struct qserver *server;
- unsigned int ipaddr, i;
- unsigned short port;
- int n_servers, new_server, port_adjust= 0;
- char *pkt;
- server_type* server_type;
- FILE *outfile;
-
- for ( server= servers; server != NULL; server= server->next) {
- if ( !server->type->master || server->master_pkt == NULL)
- continue;
- pkt= server->master_pkt;
-
- if ( server->query_arg && server->type->id == GAMESPY_MASTER) {
- server_type= find_server_type_string( server->query_arg);
- if ( server_type == NULL)
- server_type= find_server_type_id( server->type->master);
- }
- else
- server_type= find_server_type_id( server->type->master);
-
- if ( server->type->id == GAMESPY_MASTER && server_type) {
- if ( server_type->id == UN_SERVER)
- port_adjust= -1;
- else if ( server_type->id == KINGPIN_SERVER)
- port_adjust= 10;
- }
-
- outfile= NULL;
- if ( server->outfilename) {
- if ( strcmp( server->outfilename, "-") == 0)
- outfile= stdout;
- else
- outfile= fopen( server->outfilename, "w");
- if ( outfile == NULL) {
- perror( server->outfilename);
- continue;
- }
- }
- n_servers= 0;
- for ( i= 0; i < server->master_pkt_len; i+= 6) {
- memcpy( &ipaddr, &pkt[i], 4);
- memcpy( &port, &pkt[i+4], 2);
- ipaddr= ntohl( ipaddr);
- port= ntohs( port) + port_adjust;
- new_server= 1;
- if ( outfile)
- fprintf( outfile, "%s %d.%d.%d.%d:%hu\n",
- server_type ? server_type->type_string : "",
- (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff, port);
- else if ( server_type == NULL)
- fprintf( OF, "%d.%d.%d.%d:%hu\n",
- (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff, port);
- else
- add_qserver_byaddr( ipaddr, port, server_type, &new_server);
- n_servers+= new_server;
- }
- free( server->master_pkt);
- server->master_pkt= NULL;
- server->master_pkt_len= 0;
- server->n_servers= n_servers;
- if ( outfile)
- fclose( outfile);
- }
- if ( hostname_lookup)
- hcache_update_file();
- bind_sockets();
- }
-
- void
- init_qserver( struct qserver *server)
- {
- server->server_name= NULL;
- server->map_name= NULL;
- server->game= NULL;
- server->num_players= 0;
- server->fd= -1;
- if ( server->flags & FLAG_BROADCAST) {
- server->retry1= 1;
- server->retry2= 1;
- }
- else {
- server->retry1= n_retries;
- server->retry2= n_retries;
- }
- server->n_retries= 0;
- server->ping_total= 0;
- server->n_packets= 0;
- server->n_requests= 0;
-
- server->n_servers= 0;
- server->master_pkt_len= 0;
- server->master_pkt= NULL;
- server->error= NULL;
-
- server->saved_data.data= NULL;
- server->saved_data.datalen= 0;
- server->saved_data.pkt_index= -1;
- server->saved_data.pkt_max= 0;
- server->saved_data.next= NULL;
-
- server->next_rule= (get_server_rules) ? "" : NO_SERVER_RULES;
- server->next_player_info= (get_player_info) ? 0 : NO_PLAYER_INFO;
-
- server->n_player_info= 0;
- server->players= NULL;
- server->n_rules= 0;
- server->rules= NULL;
- server->last_rule= &server->rules;
- server->missing_rules= 0;
-
- num_servers_total++;
- }
-
- struct qserver *
- find_server_by_address( unsigned int ipaddr, unsigned short port)
- {
- struct qserver **server;
- unsigned int hash, i;
- hash= (ipaddr + port) % ADDRESS_HASH_LENGTH;
-
- if ( ipaddr == 0) {
- for ( hash= 0; hash < ADDRESS_HASH_LENGTH; hash++)
- printf( "%3d %d\n", hash, server_hash_len[hash]);
- return NULL;
- }
-
- server= server_hash[hash];
- for ( i= server_hash_len[hash]; i; i--, server++)
- if ( (*server)->ipaddr == ipaddr && (*server)->port == port)
- return *server;
- return NULL;
- }
-
- void
- add_server_to_hash( struct qserver *server)
- {
- unsigned int hash;
- hash= (server->ipaddr + server->port) % ADDRESS_HASH_LENGTH;
-
- if ( server_hash_len[hash] % 16 == 0) {
- server_hash[hash]= (struct qserver**) realloc( server_hash[hash],
- sizeof( struct qserver **) * (server_hash_len[hash]+16));
- memset( &server_hash[hash][server_hash_len[hash]], 0,
- sizeof( struct qserver **) * 16);
- }
- server_hash[hash][server_hash_len[hash]]= server;
- server_hash_len[hash]++;
- }
-
- /* Functions for binding sockets to Quake servers
- */
- int
- bind_qserver( struct qserver *server)
- {
- struct sockaddr_in addr;
- static int one= 1;
-
- if ( server->type->flags & TF_TCP_CONNECT)
- server->fd= socket( AF_INET, SOCK_STREAM, 0);
- else
- server->fd= socket( AF_INET, SOCK_DGRAM, 0);
-
- if ( server->fd == INVALID_SOCKET) {
- if ( sockerr() == EMFILE) {
- server->fd= -1;
- return -2;
- }
- perror( "socket" );
- server->server_name= SYSERROR;
- return -1;
- }
-
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl( source_ip);
- if ( server->type->id == Q2_MASTER)
- addr.sin_port= htons(26500);
- else if ( source_port == 0)
- addr.sin_port= 0;
- else {
- addr.sin_port= htons( source_port);
- source_port++;
- if ( source_port > source_port_high)
- source_port= source_port_low;
- }
- memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero) );
-
- if ( bind( server->fd, (struct sockaddr *)&addr,
- sizeof(struct sockaddr)) == SOCKET_ERROR) {
- if ( sockerr() != EADDRINUSE) {
- perror( "bind" );
- server->server_name= SYSERROR;
- }
- close(server->fd);
- server->fd= -1;
- return -1;
- }
-
- if ( server->flags & FLAG_BROADCAST)
- setsockopt( server->fd, SOL_SOCKET, SO_BROADCAST, (char*)&one,
- sizeof(one));
-
- if ( server->type->id != Q2_MASTER &&
- !(server->flags & FLAG_BROADCAST)) {
- addr.sin_family= AF_INET;
- addr.sin_port= htons(server->port + server->type->port_offset);
- addr.sin_addr.s_addr= server->ipaddr;
- memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero) );
-
- if ( connect( server->fd, (struct sockaddr *)&addr, sizeof(addr)) ==
- SOCKET_ERROR) {
- if ( server->type->id == UN_MASTER) {
- if ( connection_refused()) {
- /* server->fd= -2; */
- /* set up for connect retry */
- }
- }
- perror( "connect");
- server->server_name= SYSERROR;
- close(server->fd);
- server->fd= -1;
- return -1;
- }
- }
-
- if ( server->type->flags & TF_TCP_CONNECT) {
- int one= 1;
- set_non_blocking( server->fd);
- setsockopt( server->fd, IPPROTO_TCP, TCP_NODELAY,
- (char*) &one, sizeof(one));
- }
-
- #ifdef _ISUNIX
- if ( server->fd >= max_connmap) {
- int old_max= max_connmap;
- max_connmap= server->fd + 32;
- connmap= (struct qserver **) realloc( connmap, max_connmap *
- sizeof( struct qserver *));
- memset( &connmap[old_max], 0, (max_connmap - old_max) *
- sizeof( struct qserver *));
- }
- connmap[server->fd]= server;
- #endif
- #ifdef _WIN32
- { int i;
- for ( i= 0; i < max_connmap; i++) {
- if ( connmap[i] == NULL) {
- connmap[i]= server;
- break;
- }
- }
- if ( i >= max_connmap) printf( "could not put server in connmap\n");
- }
- #endif
-
- return 0;
- }
-
- int
- bind_sockets()
- {
- struct qserver *server;
- int rc, retry_count= 0;;
-
- if ( !waiting_for_masters) {
- if ( last_server_bind == NULL)
- last_server_bind= servers;
- server= last_server_bind;
- }
- else
- server= servers;
-
- for ( ; server != NULL && connected < max_simultaneous;
- server= server->next) {
- if ( server->server_name == NULL && server->fd == -1) {
- if ( waiting_for_masters && !server->type->master)
- continue;
- if ( (rc= bind_qserver( server)) == 0) {
- server->type->status_query_func( server);
- connected++;
- if ( !waiting_for_masters)
- last_server_bind= server;
- }
- else if ( rc == -2 && ++retry_count > 2)
- return -2;
- }
- }
- if ( ! connected && retry_count)
- return -2;
- return 0;
- }
-
-
- /* Functions for sending packets
- */
- void
- send_packets()
- {
- struct qserver *server= servers;
- struct timeval now;
- int interval, n_sent=0, prev_n_sent;
-
- gettimeofday( &now, NULL);
-
- for ( ; server != NULL; server= server->next) {
- if ( server->fd == -1)
- continue;
- if ( server->type->id & MASTER_SERVER)
- interval= master_retry_interval;
- else
- interval= retry_interval;
- prev_n_sent= n_sent;
- if ( server->server_name == NULL ||
- !(server->type->flags & TF_SINGLE_QUERY) ) {
- if ( server->retry1 != n_retries &&
- time_delta( &now, &server->packet_time1) <
- (interval*(n_retries-server->retry1+1)))
- continue;
- if ( ! server->retry1) {
- cleanup_qserver( server, 1);
- continue;
- }
- server->type->status_query_func( server);
- n_sent++;
- continue;
- }
- if ( server->next_rule != NO_SERVER_RULES) {
- if ( server->retry1 != n_retries &&
- time_delta( &now, &server->packet_time1) <
- (interval*(n_retries-server->retry1+1)))
- continue;
- if ( ! server->retry1) {
- server->next_rule= NULL;
- server->missing_rules= 1;
- cleanup_qserver( server, 0);
- continue;
- }
- send_rule_request_packet( server);
- n_sent++;
- }
- if ( server->next_player_info < server->num_players &&
- server->type->player_packet) {
- if ( server->retry2 != n_retries &&
- time_delta( &now, &server->packet_time2) <
- (interval*(n_retries-server->retry2+1)))
- continue;
- if ( ! server->retry2) {
- server->next_player_info++;
- if ( server->next_player_info >= server->num_players) {
- cleanup_qserver( server, 0);
- continue;
- }
- server->retry2= n_retries;
- }
- send_player_request_packet( server);
- n_sent++;
- }
- if ( prev_n_sent == n_sent) {
- if ( ! server->retry1 && time_delta( &now, &server->packet_time1) >
- (interval*(n_retries+1)))
- cleanup_qserver( server, 1);
- }
- }
- }
-
- int
- send_broadcast( struct qserver *server, char *pkt, int pktlen)
- {
- struct sockaddr_in addr;
- addr.sin_family= AF_INET;
- addr.sin_port= htons(server->port + server->type->port_offset);
- addr.sin_addr.s_addr= server->ipaddr;
- memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero));
- return sendto( server->fd, (const char*) pkt, pktlen, 0,
- (struct sockaddr *) &addr, sizeof(addr));
- }
-
- /* server starts sending data immediately, so we need not do anything */
- void
- send_bfris_request_packet( struct qserver *server)
- {
-
- if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
-
- server->retry1--;
- server->n_packets++;
- }
-
-
- /* First packet for a normal Quake server
- */
- void
- send_qserver_request_packet( struct qserver *server)
- {
- int rc;
- if ( server->flags & FLAG_BROADCAST)
- rc= send_broadcast( server, server->type->status_packet,
- server->type->status_len);
- else
- rc= send( server->fd, server->type->status_packet,
- server->type->status_len, 0);
-
- if ( rc == SOCKET_ERROR) {
- unsigned int ipaddr= ntohl(server->ipaddr);
- fprintf( stderr,
- "Error on %d.%d.%d.%d, skipping ...\n",
- (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff);
- perror( "send");
- cleanup_qserver( server, 1);
- return;
- }
- if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
- server->retry1--;
- server->n_packets++;
- }
-
- /* First packet for a QuakeWorld server
- */
- void
- send_qwserver_request_packet( struct qserver *server)
- {
- int rc;
-
- if ( server->flags & FLAG_BROADCAST)
- rc= send_broadcast( server, server->type->status_packet,
- server->type->status_len);
- else if ( server->server_name == NULL)
- rc= send( server->fd, server->type->status_packet,
- server->type->status_len, 0);
- else if ( server->server_name != NULL && server->type->rule_packet)
- rc= send( server->fd, server->type->rule_packet,
- server->type->rule_len, 0);
- else
- rc= SOCKET_ERROR;
-
- if ( rc == SOCKET_ERROR) {
- unsigned int ipaddr= ntohl(server->ipaddr);
- fprintf( stderr,
- "Error on %d.%d.%d.%d, skipping ...\n",
- (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff);
- perror( "send");
- cleanup_qserver( server, 1);
- return;
- }
- if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else if ( server->server_name == NULL)
- server->n_retries++;
- server->retry1--;
- if ( server->server_name == NULL)
- server->n_packets++;
- }
-
- /* First packet for an Unreal server
- */
- void
- send_unreal_request_packet( struct qserver *server)
- {
- int rc;
-
- if ( server->flags & FLAG_BROADCAST)
- rc= send_broadcast( server, server->type->status_packet,
- server->type->status_len);
- else
- rc= send( server->fd, server->type->status_packet,
- server->type->status_len, 0);
-
- if ( rc == SOCKET_ERROR)
- perror( "send");
- if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
- server->retry1--;
- server->n_packets++;
- }
-
- /* First packet for an Unreal master
- */
- void
- send_unrealmaster_request_packet( struct qserver *server)
- {
- int rc;
-
- rc= send( server->fd, server->type->status_packet,
- server->type->status_len, 0);
-
- if ( rc == SOCKET_ERROR)
- perror( "send");
- if ( server->retry1 == n_retries) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
- server->retry1--;
- server->n_packets++;
- }
-
- char *
- build_hlmaster_packet( struct qserver *server, int *len)
- {
- static char packet[1600];
- char *pkt, *r, *sep= "";
- char *gamedir, *map, *flags;
- int flen;
-
- pkt= &packet[0];
- memcpy( pkt, server->type->master_packet, server->type->master_len);
-
- pkt+= server->type->master_len;
-
- gamedir= get_param_value( server, "game", NULL);
- if ( gamedir)
- pkt+= sprintf( pkt, "\\gamedir\\%s", gamedir);
- map= get_param_value( server, "map", NULL);
- if ( map)
- pkt+= sprintf( pkt, "\\map\\%s", map);
-
- flags= get_param_value( server, "status", NULL);
- r= flags;
- while ( flags && sep) {
- sep= strchr( r, ':');
- if ( sep)
- flen= sep-r;
- else
- flen= strlen( r);
- if ( strncmp( r, "notempty", flen) == 0)
- pkt+= sprintf( pkt, "\\empty\\1");
- else if ( strncmp( r, "notfull", flen) == 0)
- pkt+= sprintf( pkt, "\\full\\1");
- else if ( strncmp( r, "dedicated", flen) == 0)
- pkt+= sprintf( pkt, "\\dedicated\\1");
- else if ( strncmp( r, "linux", flen) == 0)
- pkt+= sprintf( pkt, "\\linux\\1");
- r= sep+1;
- }
-
- *len= pkt - packet;
-
- return packet;
- }
-
- /* First packet for a QuakeWorld master server
- */
- void
- send_qwmaster_request_packet( struct qserver *server)
- {
- int rc= 0, query_len= 0;
- char query_buf[4096];
-
- if ( server->type->master_len == 0) {
- char *master_protocol= server->query_arg;
- if ( master_protocol == NULL)
- master_protocol= server->type->master_protocol;
- query_len= sprintf( query_buf, server->type->master_packet,
- master_protocol?master_protocol:"",
- server->type->master_query?server->type->master_query:"");
- }
-
- if ( server->type->id == Q2_MASTER) {
- struct sockaddr_in addr;
- addr.sin_family= AF_INET;
- addr.sin_port= htons(server->port + server->type->port_offset);
- addr.sin_addr.s_addr= server->ipaddr;
- memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero));
- rc= sendto( server->fd, server->type->master_packet,
- server->type->master_len, 0,
- (struct sockaddr *) &addr, sizeof(addr));
- }
- else {
- char *packet;
- int packet_len;
- if ( query_len) {
- packet= query_buf;
- packet_len= query_len;
- }
- else {
- packet= server->type->master_packet;
- packet_len= server->type->master_len;
- }
- if ( server->type->id == HL_MASTER) {
- memcpy( server->type->master_packet+1, server->master_query_tag, 3);
- if ( server->query_arg)
- packet= build_hlmaster_packet( server, &packet_len);
- }
- rc= send( server->fd, packet, packet_len, 0);
- }
-
- if ( rc == SOCKET_ERROR)
- perror( "send");
- if ( server->retry1 == n_retries) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
- server->retry1--;
- server->n_packets++;
- }
-
- void
- send_tribes_request_packet( struct qserver *server)
- {
- int rc;
-
- if ( get_player_info || get_server_rules) {
- if ( server->flags & FLAG_BROADCAST && server->server_name == NULL)
- rc= send_broadcast( server, server->type->player_packet,
- server->type->player_len);
- else
- rc= send( server->fd, server->type->player_packet,
- server->type->player_len, 0);
- }
- else {
- if ( server->flags & FLAG_BROADCAST && server->server_name == NULL)
- rc= send_broadcast( server, server->type->status_packet,
- server->type->status_len);
- else
- rc= send( server->fd, server->type->status_packet,
- server->type->status_len, 0);
- }
-
- if ( rc == SOCKET_ERROR)
- perror( "send");
- if ( server->retry1 == n_retries) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
- server->retry1--;
- server->n_packets++;
- }
-
- void
- send_tribes2_request_packet( struct qserver *server)
- {
- int rc;
-
- if ( server->flags & FLAG_BROADCAST && server->server_name == NULL)
- rc= send_broadcast( server, server->type->status_packet,
- server->type->status_len);
- else if ( server->server_name == NULL)
- rc= send( server->fd, server->type->status_packet,
- server->type->status_len, 0);
- else
- rc= send( server->fd, server->type->player_packet,
- server->type->status_len, 0);
-
- if ( rc == SOCKET_ERROR)
- perror( "send");
- if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
- server->retry1--;
- server->n_packets++;
- }
-
- void
- send_tribes2master_request_packet( struct qserver *server)
- {
- int rc;
- unsigned char packet[1600], *pkt;
- unsigned int len, min_players, max_players, region_mask=0;
- unsigned int build_version, max_bots, min_cpu, status;
- char *game, *mission, *buddies;
- static char *region_list[]= { "naeast", "nawest", "sa", "aus", "asia", "eur", NULL };
- static char *status_list[]= { "dedicated", "nopassword", "linux" };
-
- if ( strcmp( get_param_value( server, "query", ""), "types") == 0) {
- rc= send( server->fd, tribes2_game_types_request,
- sizeof(tribes2_game_types_request), 0);
- goto send_done;
- }
-
- memcpy( packet, server->type->master_packet, server->type->master_len);
-
- pkt= packet + 7;
-
- game= get_param_value( server, "game", "any");
- len= strlen(game);
- if ( len > 255) len= 255;
- *pkt++= len;
- memcpy( pkt, game, len);
- pkt+= len;
-
- mission= get_param_value( server, "mission", "any");
- len= strlen(mission);
- if ( len > 255) len= 255;
- *pkt++= len;
- memcpy( pkt, mission, len);
- pkt+= len;
-
- min_players= get_param_ui_value( server, "minplayers", 0);
- max_players= get_param_ui_value( server, "maxplayers", 255);
- *pkt++= min_players;
- *pkt++= max_players;
-
- region_mask= get_param_ui_value( server, "regions", 0xffffffff);
- if ( region_mask == 0) {
- char *regions= get_param_value( server, "regions", "");
- char *r= regions;
- char **list, *sep;
- do {
- sep= strchr( r, ':');
- if ( sep)
- len= sep-r;
- else
- len= strlen( r);
- for ( list= region_list; *list; list++)
- if ( strncasecmp( r, *list, len) == 0)
- break;
- if ( *list)
- region_mask|= 1<<(list-region_list);
- r= sep+1;
- } while ( sep);
- }
- if ( little_endian)
- memcpy( pkt, ®ion_mask, 4);
- else {
- pkt[0]= region_mask&0xff;
- pkt[1]= (region_mask>>8)&0xff;
- pkt[2]= (region_mask>>16)&0xff;
- pkt[3]= (region_mask>>24)&0xff;
- }
- pkt+= 4;
-
- build_version= get_param_ui_value( server, "build", 0);
- /*
- if ( build_version && build_version < 22337) {
- packet[1]= 0;
- build_version= 0;
- }
- */
- if ( little_endian)
- memcpy( pkt, &build_version, 4);
- else {
- pkt[0]= build_version&0xff;
- pkt[1]= (build_version>>8)&0xff;
- pkt[2]= (build_version>>16)&0xff;
- pkt[3]= (build_version>>24)&0xff;
- }
- pkt+= 4;
-
- status= get_param_ui_value( server, "status", -1);
- if ( status == 0) {
- char *flags= get_param_value( server, "status", "");
- char *r= flags;
- char **list, *sep;
- do {
- sep= strchr( r, ':');
- if ( sep)
- len= sep-r;
- else
- len= strlen( r);
- for ( list= status_list; *list; list++)
- if ( strncasecmp( r, *list, len) == 0)
- break;
- if ( *list)
- status|= 1<<(list-status_list);
- r= sep+1;
- } while ( sep);
- }
- else if ( status == -1)
- status= 0;
- *pkt++= status;
-
- max_bots= get_param_ui_value( server, "maxbots", 255);
- *pkt++= max_bots;
-
- min_cpu= get_param_ui_value( server, "mincpu", 0);
- if ( little_endian)
- memcpy( pkt, &min_cpu, 2);
- else {
- pkt[0]= min_cpu&0xff;
- pkt[1]= (min_cpu>>8)&0xff;
- }
- pkt+= 2;
-
- buddies= get_param_value( server, "buddies", NULL);
- if ( buddies) {
- char *b= buddies, *sep;
- unsigned int buddy, n_buddies= 0;
- unsigned char *n_loc= pkt++;
- do {
- sep= strchr( b, ':');
- if ( sscanf( b, "%u", &buddy)) {
- n_buddies++;
- if ( little_endian)
- memcpy( pkt, &buddy, 4);
- else {
- pkt[0]= buddy&0xff;
- pkt[1]= (buddy>>8)&0xff;
- pkt[2]= (buddy>>16)&0xff;
- pkt[3]= (buddy>>24)&0xff;
- }
- pkt+= 4;
- }
- b= sep+1;
- } while ( sep && n_buddies < 255);
- *n_loc= n_buddies;
- }
- else
- *pkt++= 0;
-
- rc= send( server->fd, (char*)packet, pkt-packet, 0);
-
- send_done:
- if ( rc == SOCKET_ERROR)
- perror( "send");
- if ( server->retry1 == n_retries) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
- server->retry1--;
- server->n_packets++;
- }
-
- static struct _gamespy_query_map {
- char *qstat_type;
- char *gamespy_type;
- } gamespy_query_map[] = {
- "qws", "quakeworld",
- "q2s", "quake2",
- "q3s", "quake3",
- "tbs", "tribes",
- "uns", "ut",
- "sgs", "shogo",
- "hls", "halflife",
- "kps", "kingpin",
- "hrs", "heretic2",
- "sfs", "sofretail",
- NULL, NULL
- };
-
- void
- send_gamespy_master_request( struct qserver *server)
- {
- int rc, i;
- char request[1024];
-
- if ( server->n_packets)
- return;
-
- rc= send( server->fd, server->type->master_packet,
- server->type->master_len, 0);
- if ( rc != server->type->master_len)
- perror( "send");
-
- strcpy( request, server->type->status_packet);
-
- for ( i= 0; gamespy_query_map[i].qstat_type; i++)
- if ( strcasecmp( server->query_arg, gamespy_query_map[i].qstat_type) == 0)
- break;
- if ( gamespy_query_map[i].gamespy_type == NULL)
- strcat( request, server->query_arg);
- else
- strcat( request, gamespy_query_map[i].gamespy_type);
-
- rc= send( server->fd, request, strlen( request), 0);
- if ( rc != strlen( request))
- perror( "send");
-
- if ( server->retry1 == n_retries) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- server->n_packets++;
- }
-
- void
- send_rule_request_packet( struct qserver *server)
- {
- int rc, len;
-
- /* Server created via broadcast, so bind it */
- if ( server->fd == -1) {
- if ( bind_qserver( server) < 0)
- goto setup_retry;
- }
-
- if ( server->type->id == Q_SERVER) {
- strcpy( (char*)q_rule.data, server->next_rule);
- len= Q_HEADER_LEN + strlen((char*)q_rule.data) + 1;
- q_rule.length= htons( (short)len);
- }
- else
- len= server->type->rule_len;
-
- rc= send( server->fd, (const char *) server->type->rule_packet,
- len, 0);
- if ( rc == SOCKET_ERROR)
- perror( "send");
-
- setup_retry:
- if ( server->retry1 == n_retries) {
- gettimeofday( &server->packet_time1, NULL);
- server->n_requests++;
- }
- else if ( server->server_name == NULL)
- server->n_retries++;
- server->retry1--;
- if ( server->server_name == NULL)
- server->n_packets++;
- }
-
- void
- send_player_request_packet( struct qserver *server)
- {
- int rc;
-
- /* Server created via broadcast, so bind it */
- if ( server->fd == -1) {
- if ( bind_qserver( server) < 0)
- goto setup_retry;
- }
-
- if ( server->type->id == Q_SERVER)
- q_player.data[0]= server->next_player_info;
- rc= send( server->fd, (const char *) server->type->player_packet,
- server->type->player_len, 0);
- if ( rc == SOCKET_ERROR)
- perror( "send");
-
- setup_retry:
- if ( server->retry2 == n_retries) {
- gettimeofday( &server->packet_time2, NULL);
- server->n_requests++;
- }
- else
- server->n_retries++;
- server->retry2--;
- server->n_packets++;
- }
-
- /* Functions for figuring timeouts and when to give up
- */
- void
- cleanup_qserver( struct qserver *server, int force)
- {
- int close_it= force, i;
- if ( server->server_name == NULL) {
- close_it= 1;
- if ( server->type->id & MASTER_SERVER && server->master_pkt != NULL)
- server->server_name= MASTER;
- else {
- server->server_name= TIMEOUT;
- num_servers_timed_out++;
- }
- }
- else if ( server->type->flags & TF_SINGLE_QUERY)
- close_it= 1;
- else if ( server->next_rule == NO_SERVER_RULES &&
- server->next_player_info >= server->num_players)
- close_it= 1;
-
- if ( close_it) {
-
- if ( server->saved_data.data) {
- SavedData *sdata= server->saved_data.next;
- free(server->saved_data.data);
- server->saved_data.data= NULL;
- while ( sdata != NULL) {
- SavedData *next;
- free(sdata->data);
- next= sdata->next;
- free(sdata);
- sdata= next;
- }
- server->saved_data.next= NULL;
- }
-
- if ( server->fd != -1) {
- close( server->fd);
- #ifdef _ISUNIX
- connmap[server->fd]= NULL;
- #endif
- #ifdef _WIN32
- for ( i= 0; i < max_connmap; i++) {
- if ( connmap[i] == server) {
- connmap[i]= NULL;
- break;
- }
- }
- #endif
- server->fd= -1;
- connected--;
- }
-
- if ( server->server_name != TIMEOUT) {
- num_servers_returned++;
- if ( server->server_name != DOWN)
- num_players_total+= server->num_players;
- }
- if ( server->server_name == TIMEOUT || server->server_name == DOWN)
- server->ping_total= 999999;
- if ( server->type->master) {
- waiting_for_masters--;
- if ( waiting_for_masters == 0)
- add_servers_from_masters();
- }
- if ( ! server_sort)
- display_server( server);
- }
- }
-
- void
- get_next_timeout( struct timeval *timeout)
- {
- struct qserver *server= servers;
- struct timeval now;
- int diff1, diff2, diff, smallest= retry_interval+master_retry_interval;
- int interval, bind_count= 0;
- static struct qserver *first_server_bind= NULL;
-
- if ( first_server_bind == NULL)
- first_server_bind= servers;
-
- server= first_server_bind;
-
- for ( ; server != NULL && server->fd == -1; server= server->next)
- ;
- if ( server == NULL) {
- timeout->tv_sec= 0;
- timeout->tv_usec= 10 * 1000;
- return;
- }
- first_server_bind= server;
-
- gettimeofday( &now, NULL);
- for ( ; server != NULL && bind_count < connected; server= server->next) {
- if ( server->fd == -1)
- continue;
- if ( server->type->id & MASTER_SERVER)
- interval= master_retry_interval;
- else
- interval= retry_interval;
- diff2= 0xffff;
- diff1= 0xffff;
- if ( server->server_name == NULL)
- diff1= interval*(n_retries-server->retry1+1) -
- time_delta( &now, &server->packet_time1);
- else {
- if ( server->next_rule != NULL)
- diff1= interval*(n_retries-server->retry1+1) -
- time_delta( &now, &server->packet_time1);
- if ( server->next_player_info < server->num_players)
- diff2= interval*(n_retries-server->retry2+1) -
- time_delta( &now, &server->packet_time2);
- }
- diff= (diff1<diff2)?diff1:diff2;
- if ( diff < smallest)
- smallest= diff;
- bind_count++;
- }
- if ( smallest < 10)
- smallest= 10;
- timeout->tv_sec= smallest / 1000;
- timeout->tv_usec= (smallest % 1000) * 1000;
- }
-
-
- #ifdef USE_SELECT
- static fd_set select_read_fds;
- static int select_maxfd;
- static int select_cursor;
-
- int
- set_fds( fd_set *fds)
- {
- int maxfd= 1, i;
-
- for ( i= 0; i < max_connmap; i++)
- if ( connmap[i] != NULL) {
- FD_SET( connmap[i]->fd, fds);
- if ( connmap[i]->fd > maxfd)
- maxfd= connmap[i]->fd;
- }
-
- return maxfd;
- }
-
- void
- set_file_descriptors()
- {
- FD_ZERO( &select_read_fds);
- select_maxfd= set_fds( &select_read_fds);
- }
-
- int
- wait_for_file_descriptors( struct timeval *timeout)
- {
- select_cursor= 0;
- return select( select_maxfd+1, &select_read_fds, NULL, NULL, timeout);
- }
-
- struct qserver *
- get_next_ready_server()
- {
- while ( select_cursor < max_connmap &&
- ( connmap[select_cursor] == NULL ||
- ! FD_ISSET( connmap[select_cursor]->fd, &select_read_fds)) )
- select_cursor++;
- if ( select_cursor >= max_connmap)
- return NULL;
- return connmap[select_cursor++];
- }
-
- int
- wait_for_timeout( unsigned int ms)
- {
- struct timeval timeout;
- timeout.tv_sec= ms/1000;
- timeout.tv_usec= (ms%1000) * 1000;
- return select( 0, 0, NULL, NULL, &timeout);
- }
-
- #endif /* USE_SELECT */
-
- #ifdef USE_POLL
- static struct pollfd *pollfds;
- static int n_pollfds;
- static int max_pollfds= 0;
- static int poll_cursor;
-
- void
- set_file_descriptors()
- {
- struct pollfd *p;
- int i;
-
- if ( max_connmap > max_pollfds) {
- max_pollfds= max_connmap;
- pollfds= (struct pollfd *) realloc( pollfds, max_pollfds *
- sizeof(struct pollfd));
- }
-
- p= pollfds;
- for ( i= 0; i < max_connmap; i++)
- if ( connmap[i] != NULL) {
- p->fd= connmap[i]->fd;
- p->events= POLLIN;
- p->revents= 0;
- p++;
- }
- n_pollfds= p - pollfds;
- }
-
- int
- wait_for_file_descriptors( struct timeval *timeout)
- {
- poll_cursor= 0;
- return poll( pollfds, n_pollfds, timeout->tv_sec*1000 + timeout->tv_usec/1000);
- }
-
- struct qserver *
- get_next_ready_server()
- {
- for ( ; poll_cursor < n_pollfds; poll_cursor++)
- if ( pollfds[ poll_cursor].revents)
- break;
- if ( poll_cursor >= n_pollfds)
- return NULL;
- return connmap[pollfds[poll_cursor++].fd];
- }
-
- int
- wait_for_timeout( unsigned int ms)
- {
- return poll( 0, 0, ms);
- }
-
- #endif /* USE_POLL */
-
-
-
- /* Functions for handling response packets
- */
-
- /* Packet from normal Quake server
- */
- void
- deal_with_q_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- struct q_packet *pkt= (struct q_packet *)rawpkt;
- int rc;
-
- if ( ntohs( pkt->length) != pktlen) {
- fprintf( stderr, "%s Ignoring bogus packet; length %d != %d\n",
- server->arg, ntohs( pkt->length), pktlen);
- cleanup_qserver(server,FORCE);
- return;
- }
-
- rawpkt[pktlen]= '\0';
-
- switch ( pkt->op_code) {
- case Q_CCREP_ACCEPT:
- case Q_CCREP_REJECT:
- return;
- case Q_CCREP_SERVER_INFO:
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time1);
- rc= server_info_packet( server, pkt, pktlen-Q_HEADER_LEN);
- break;
- case Q_CCREP_PLAYER_INFO:
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time2);
- rc= player_info_packet( server, pkt, pktlen-Q_HEADER_LEN);
- break;
- case Q_CCREP_RULE_INFO:
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time1);
- rc= rule_info_packet( server, pkt, pktlen-Q_HEADER_LEN);
- break;
- case Q_CCREQ_CONNECT:
- case Q_CCREQ_SERVER_INFO:
- case Q_CCREQ_PLAYER_INFO:
- case Q_CCREQ_RULE_INFO:
- default:
- return;
- }
-
- if ( rc == -1)
- fprintf( stderr, "%s error on packet opcode %x\n", server->arg,
- (int)pkt->op_code);
-
- cleanup_qserver( server, (rc == -1) ? FORCE : 0);
- }
-
- /* Packet from QuakeWorld server
- */
- void
- deal_with_qw_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- if ( server->server_name == NULL)
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time1);
-
- if ( ((rawpkt[0] != '\377' && rawpkt[0] != '\376') || rawpkt[1] != '\377' ||
- rawpkt[2] != '\377' || rawpkt[3] != '\377') && show_errors) {
- unsigned int ipaddr= ntohl(server->ipaddr);
- fprintf( stderr,
- "Odd packet from server %d.%d.%d.%d:%hu, processing ...\n",
- (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff, ntohs(server->port));
- print_packet( server, rawpkt, pktlen);
- }
-
- rawpkt[pktlen]= '\0';
-
- if ( rawpkt[4] == 'n') {
- if ( server->type->id != QW_SERVER)
- server->type= find_server_type_id( QW_SERVER);
- deal_with_q1qw_packet( server, rawpkt, pktlen);
- return;
- }
- else if ( rawpkt[4] == '\377' && rawpkt[5] == 'n') {
- if ( server->type->id != HW_SERVER)
- server->type= find_server_type_id( HW_SERVER);
- deal_with_q1qw_packet( server, rawpkt, pktlen);
- return;
- }
- else if ( strncmp( &rawpkt[4], "print\n\\", 7) == 0) {
- deal_with_q2_packet( server, rawpkt+10, pktlen-10, 0);
- return;
- }
- else if ( strncmp( &rawpkt[4], "print\n", 6) == 0) {
- /* work-around for occasional bug in Quake II status packets
- */
- char *c, *p;
- p= c= &rawpkt[10];
- while ( *p != '\\' && (c= strchr( p, '\n')))
- p= c+1;
- if ( *p == '\\' && c != NULL) {
- deal_with_q2_packet( server, p, pktlen-(p-rawpkt), 0);
- return;
- }
- }
- else if ( strncmp( &rawpkt[4], "infoResponse", 12) == 0 ||
- (rawpkt[4] == '\001' && strncmp( &rawpkt[5], "infoResponse", 12) == 0) ) {
- /* quake3 info response */
- if ( rawpkt[4] == '\001') {
- rawpkt++;
- pktlen--;
- }
- rawpkt+= 12;
- pktlen-= 12;
- for ( ; pktlen && *rawpkt != '\\'; pktlen--, rawpkt++)
- ;
- if ( !pktlen)
- return;
- if ( rawpkt[pktlen-1] == '"') {
- rawpkt[pktlen-1]= '\0';
- pktlen--;
- }
- if ( get_player_info || get_server_rules)
- server->next_rule= "";
- deal_with_q2_packet( server, rawpkt, pktlen, 0);
- if ( (get_player_info || get_server_rules) && server->fd != -1) {
- send_rule_request_packet( server);
- server->retry1= n_retries-1;
- }
- return;
- }
- else if ( strncmp( &rawpkt[4], "statusResponse\n", 15) == 0 ||
- (rawpkt[4] == '\001' && strncmp( &rawpkt[5], "statusResponse\n", 15) == 0) ) {
- /* quake3 status response */
- server->next_rule= NO_SERVER_RULES;
- server->next_player_info= server->max_players;
- if ( rawpkt[4] == '\001') {
- rawpkt++;
- pktlen--;
- }
- deal_with_q2_packet( server, rawpkt + 19, pktlen - 19,
- CHECK_DUPLICATE_RULES);
- return;
- }
- else if ( strncmp( &rawpkt[4], "infostringresponse", 19) == 0) {
- deal_with_q2_packet( server, rawpkt+23, pktlen-23, 0);
- return;
- }
-
- if ( show_errors) {
- unsigned int ipaddr= ntohl(server->ipaddr);
- fprintf( stderr,
- "Odd packet from server %d.%d.%d.%d:%hu, ignoring ...\n",
- (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff, ntohs(server->port));
- print_packet( server, rawpkt, pktlen);
- cleanup_qserver( server, 1);
- }
- else
- cleanup_qserver( server, 0);
- }
-
- void
- deal_with_q1qw_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- char *key, *value, *end;
- struct rule *rule;
- struct player *player= NULL, **last_player= &server->players;
- int len, rc, complete= 0;
- int number, frags, connect_time, ping;
- char *pkt= &rawpkt[5];
-
- if ( server->type->id == HW_SERVER)
- pkt= &rawpkt[6];
-
- while ( *pkt && pkt-rawpkt < pktlen) {
- if ( *pkt == '\\') {
- pkt++;
- end= strchr( pkt, '\\');
- if ( end == NULL)
- break;
- *end= '\0';
- key= pkt;
- pkt+= strlen(pkt)+1;
- end= strchr( pkt, '\\');
- if ( end == NULL)
- end= strchr( pkt, '\n');
- value= (char*) malloc(end-pkt+1);
- memcpy( value, pkt, end-pkt);
- value[end-pkt]= '\0';
- pkt= end;
- if ( strcmp( key, "hostname") == 0)
- server->server_name= value;
- else if ( strcmp( key, "map") == 0)
- server->map_name= value;
- else if ( strcmp( key, "maxclients") == 0) {
- server->max_players= atoi(value);
- free( value);
- }
- else if ( get_server_rules || strncmp( key, "*game", 5) == 0) {
- add_rule( server, key, value, NO_VALUE_COPY);
- if ( strcmp( key, "*gamedir") == 0)
- server->game= value;
- }
- }
- else if ( *pkt == '\n') {
- pkt++;
- if ( pkt-rawpkt>=pktlen || *pkt == '\0')
- break;
- rc= sscanf( pkt, "%d %d %d %d %n", &number, &frags, &connect_time,
- &ping, &len);
- if ( rc != 4) {
- char *nl; /* assume it's an error packet */
- server->error= (char*)malloc( pktlen+1);
- nl= strchr( pkt, '\n');
- if ( nl != NULL) {
- strncpy( server->error, pkt, nl-pkt);
- server->error[nl-pkt]= '\0';
- }
- else
- strcpy( server->error, pkt);
- server->server_name= SERVERERROR;
- complete= 1;
- break;
- }
- if ( get_player_info) {
- player= (struct player *) calloc( 1, sizeof( struct player));
- player->number= number;
- player->frags= frags;
- player->connect_time= connect_time * 60;
- player->ping= ping;
- }
- else
- player= NULL;
-
- pkt+= len;
-
- if ( *pkt != '"') break;
- pkt++;
- end= strchr( pkt, '"');
- if ( end == NULL) break;
- if ( player != NULL) {
- player->name= (char*) malloc(end-pkt+1);
- memcpy( player->name, pkt, end-pkt);
- player->name[end-pkt]= '\0';
- }
- pkt= end+2;
-
- if ( *pkt != '"') break;
- pkt++;
- end= strchr( pkt, '"');
- if ( end == NULL) break;
- if ( player != NULL) {
- player->skin= (char*) malloc(end-pkt+1);
- memcpy( player->skin, pkt, end-pkt);
- player->skin[end-pkt]= '\0';
- }
- pkt= end+2;
-
- if ( player != NULL) {
- sscanf( pkt, "%d %d%n", &player->shirt_color,
- &player->pants_color, &len);
- *last_player= player;
- last_player= & player->next;
- }
- else
- sscanf( pkt, "%*d %*d%n", &len);
- pkt+= len;
-
- server->num_players++;
- }
- else
- pkt++;
- complete= 1;
- }
-
- if ( !complete) {
- if ( rawpkt[4] != 'n' || rawpkt[5] != '\0') {
- fprintf( stderr,
- "Odd packet from QW server %d.%d.%d.%d:%hu ...\n",
- (server->ipaddr>>24)&0xff, (server->ipaddr>>16)&0xff,
- (server->ipaddr>>8)&0xff, server->ipaddr&0xff,
- ntohs(server->port));
- print_packet( server, rawpkt, pktlen);
- }
- }
- else if ( server->server_name == NULL)
- server->server_name= strdup("");
-
- cleanup_qserver( server, 0);
- }
-
- void
- deal_with_q2_packet( struct qserver *server, char *rawpkt, int pktlen,
- int check_duplicate_rules)
- {
- char *key, *value, *end;
- struct rule *rule;
- struct player *player= NULL;
- struct player **last_player= & server->players;
- int len, rc, complete= 0;
- int frags=0, ping=0, num_players= 0;
- char *pkt= rawpkt;
-
- while ( *pkt && pkt-rawpkt < pktlen) {
- if ( *pkt == '\\') {
- pkt++;
- if ( *pkt == '\n' && server->type->id == SOF_SERVER)
- goto player_info;
- end= strchr( pkt, '\\');
- if ( end == NULL)
- break;
- *end= '\0';
- key= pkt;
- pkt+= strlen(pkt)+1;
- end= strchr( pkt, '\\');
- if ( end == NULL) {
- end= strchr( pkt, '\n');
- if ( end == NULL)
- end= rawpkt+pktlen;
- }
- value= (char*) malloc(end-pkt+1);
- memcpy( value, pkt, end-pkt);
- value[end-pkt]= '\0';
- pkt= end;
- if ( server->server_name == NULL &&
- (strcmp( key, "hostname") == 0 ||
- strcmp( key, "sv_hostname") == 0))
- server->server_name= value;
- else if ( strcmp( key, "mapname") == 0 ||
- (strcmp( key, "map") == 0 && server->map_name == NULL)) {
- if ( server->map_name != NULL)
- free( server->map_name);
- server->map_name= value;
- }
- else if ( strcmp( key, "maxclients") == 0 ||
- strcmp( key, "sv_maxclients") == 0 ||
- strcmp( key, "max") == 0) {
- if ( server->max_players == -1)
- server->next_player_info= atoi(value);
- server->max_players= atoi(value);
- /* MOHAA Q3 protocol max players is always 0 */
- if ( server->max_players == 0)
- server->max_players= -1;
- free(value);
- }
- else if ( strcmp( key, "clients") == 0 ||
- strcmp( key, "players") == 0) {
- server->num_players= atoi(value);
- free(value);
- }
- else if ( server->server_name == NULL &&
- strcmp( key, "pure") == 0) {
- add_rule( server, key, value, NO_VALUE_COPY);
- }
- else if ( get_server_rules || strncmp( key, "game", 4) == 0) {
- add_rule( server, key, value,
- NO_VALUE_COPY|check_duplicate_rules);
- if ( strcmp( key, server->type->game_rule) == 0)
- server->game= value;
- }
- }
- else if ( *pkt == '\n') {
- player_info:
- pkt++;
- if ( *pkt == '\0')
- break;
- rc= sscanf( pkt, "%d %n", &frags, &len);
- if ( rc == 1 && pkt[len] != '"') {
- pkt+= len;
- rc= sscanf( pkt, "%d %n", &ping, &len);
- }
- else if ( rc == 1) {
- /* MOHAA Q3 protocol only provides player ping */
- ping= frags;
- frags= 0;
- }
- if ( rc != 1) {
- char *nl; /* assume it's an error packet */
- server->error= (char*)malloc( pktlen+1);
- nl= strchr( pkt, '\n');
- if ( nl != NULL)
- strncpy( server->error, pkt, nl-pkt);
- else
- strcpy( server->error, pkt);
- server->server_name= SERVERERROR;
- complete= 1;
- break;
- }
- if ( get_player_info) {
- player= (struct player *) calloc( 1, sizeof( struct player));
- player->number= 0;
- player->connect_time= -1;
- player->frags= frags;
- player->ping= ping;
- }
- else
- player= NULL;
-
- pkt+= len;
-
- if ( isdigit(*pkt)) {
- /* probably an SOF2 1.01 server, includes team # */
- int team;
- rc= sscanf( pkt, "%d %n", &team, &len);
- if ( rc == 1) {
- pkt+= len;
- if ( player) {
- player->team= team;
- server->flags|= FLAG_PLAYER_TEAMS;
- }
- }
- }
-
- if ( *pkt != '"') break;
-
- pkt++;
- end= strchr( pkt, '"');
- if ( end == NULL) break;
- if ( player != NULL) {
- player->name= (char*) malloc(end-pkt+1);
- memcpy( player->name, pkt, end-pkt);
- player->name[end-pkt]= '\0';
- }
- pkt= end+1;
-
- if ( player != NULL) {
- player->skin= NULL;
- player->shirt_color= -1;
- player->pants_color= -1;
- *last_player= player;
- last_player= & player->next;
- }
- num_players++;
- }
- else
- pkt++;
- complete= 1;
- }
-
- if ( server->num_players == 0 || num_players > server->num_players)
- server->num_players= num_players;
-
- if ( !complete) {
- cleanup_qserver( server, 1);
- return;
- }
- else if ( server->server_name == NULL)
- server->server_name= strdup("");
-
- cleanup_qserver( server, 0);
- }
-
- void
- ack_descent3master_packet( struct qserver *server, char *curtok )
- {
- int rc;
- char packet[0x1e];
- memcpy( packet, descent3_masterquery,0x1a);
- packet[1]= 0x1d;
- packet[0x16]= 1;
- memcpy( packet + 0x1a, curtok, 4);
- rc= send( server->fd, packet, sizeof(packet), 0);
- if ( rc == SOCKET_ERROR)
- perror( "send");
- }
-
- /* Packet from Descent3 master server (PXO)
- */
- void
- deal_with_descent3master_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- int i= 0, lastpacket= 0;
- char *names= rawpkt + 0x1f;
- char *ips= rawpkt + 0x29f;
- char *ports= rawpkt + 0x2ef;
- /* printf ("s=%p p=%p l=%i\n",server,rawpkt,pktlen); */
- while ( i<20) {
- if ( *names) {
- char *c;
- server->master_pkt_len += 6;
- server->master_pkt= (char*)realloc( server->master_pkt,
- server->master_pkt_len);
- c= server->master_pkt + server->master_pkt_len - 6;
- memcpy( c, ips, 4);
- memcpy( c + 4, ports, 2);
- }else if (i>0)
- lastpacket= 1;
- names+= 0x20;
- ips+= 4;
- ports+= 2;
- i++;
- }
-
- ack_descent3master_packet( server, rawpkt+0x1a);
-
- server->n_servers= server->master_pkt_len / 6;
-
- server->next_player_info= -1;
- server->retry1= 0;
-
- if (lastpacket) {
- cleanup_qserver( server, 0);
- }
- }
-
- /* Packet from QuakeWorld master server
- */
- void
- deal_with_qwmaster_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time1);
-
- if ( rawpkt[0] == QW_NACK) {
- server->error= strdup( &rawpkt[2]);
- server->server_name= SERVERERROR;
- cleanup_qserver( server, 1);
- return;
- }
-
- if ( *((unsigned int*)rawpkt) == 0xffffffff) {
- rawpkt+= 4; /* QW 1.5 */
- pktlen-= 4;
- }
-
- if ( rawpkt[0] == QW_SERVERS && rawpkt[1] == QW_NEWLINE) {
- rawpkt+= 2;
- pktlen-= 2;
- }
- else if ( rawpkt[0] == HL_SERVERS && rawpkt[1] == 0x0d) {
- memcpy( server->master_query_tag, rawpkt+2, 3);
- rawpkt+= 6;
- pktlen-= 6;
- }
- else if ( strncmp( rawpkt, "servers", 7) == 0) {
- rawpkt+= 8;
- pktlen-= 8;
- }
- else if ( strncmp( rawpkt, "getserversResponse", 18) == 0) {
- char *p;
- static int q3m_debug= 0;
-
- rawpkt+= 18;
- pktlen-= 18;
-
- for ( ; *rawpkt != '\\' && pktlen; pktlen--, rawpkt++)
- ;
- if ( !pktlen)
- return;
- rawpkt++;
- pktlen--;
-
- if ( q3m_debug) printf( "q3m pktlen %d lastchar %x\n", pktlen, (unsigned int)rawpkt[pktlen-1]);
- server->master_pkt= (char*)realloc( server->master_pkt,
- server->master_pkt_len + pktlen+1);
-
- if ( server->type->id == STEF_MASTER)
- decode_stefmaster_packet( server, rawpkt, pktlen);
- else
- decode_q3master_packet( server, rawpkt, pktlen);
- if ( q3m_debug) printf( "q3m %d servers\n", server->n_servers);
-
- return;
- }
- else if ( show_errors) {
- unsigned int ipaddr= ntohl(server->ipaddr);
- fprintf( stderr,
- "Odd packet from QW master %d.%d.%d.%d, processing ...\n",
- (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff);
- print_packet( server, rawpkt, pktlen);
- }
-
- server->master_pkt= (char*)realloc( server->master_pkt,
- server->master_pkt_len+pktlen+1);
- rawpkt[pktlen]= '\0';
- memcpy( server->master_pkt+server->master_pkt_len, rawpkt, pktlen+1);
- server->master_pkt_len+= pktlen;
-
- server->n_servers= server->master_pkt_len / 6;
-
- if ( server->type->flags & TF_MASTER_MULTI_RESPONSE) {
- server->next_player_info= -1;
- server->retry1= 0;
- }
- else if ( server->type->id == HL_MASTER) {
- if ( server->master_query_tag[0] == 0 &&
- server->master_query_tag[1] == 0 &&
- server->master_query_tag[2] == 0) {
- server->server_name= MASTER;
- cleanup_qserver( server, 1);
- bind_sockets();
- }
- else {
- server->retry1++;
- send_qwmaster_request_packet( server);
- }
- }
- else {
- server->server_name= MASTER;
- cleanup_qserver( server, 0);
- bind_sockets();
- }
- }
-
- void
- decode_q3master_packet( struct qserver *server, char *pkt, int pktlen)
- {
- char *p;
-
- pkt[pktlen]= 0;
- p= pkt;
-
- while ( *p && p < &pkt[pktlen-6]) {
- memcpy( server->master_pkt + server->master_pkt_len, &p[0], 4);
- memcpy( server->master_pkt + server->master_pkt_len + 4, &p[4], 2);
- server->master_pkt_len += 6;
- p+= 6;
- while ( *p && *p == '\\')
- p++;
- }
- server->n_servers= server->master_pkt_len / 6;
- server->next_player_info= -1;
- server->retry1= 0;
- }
-
- void
- decode_stefmaster_packet( struct qserver *server, char *pkt, int pktlen)
- {
- unsigned char *p, *m, *end;
- unsigned int i, b;
-
- pkt[pktlen]= 0;
-
- p= (unsigned char*) pkt;
- m= (unsigned char*) server->master_pkt + server->master_pkt_len;
- end= (unsigned char*) &pkt[pktlen-12];
- while ( *p && p < end) {
- for ( i= 6; i; i--) {
- sscanf( (char*)p, "%2x", &b);
- p+= 2;
- *m++= b;
- }
- server->master_pkt_len += 6;
- while ( *p && *p == '\\')
- p++;
- }
- server->n_servers= server->master_pkt_len / 6;
- server->next_player_info= -1;
- server->retry1= 0;
- }
-
- /* Packet from Tribes master server
- */
- void
- deal_with_tribesmaster_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- unsigned char *upkt= (unsigned char*) rawpkt;
- int packet_number= upkt[2];
- int n_packets= upkt[3];
- unsigned char *p;
- char *mpkt;
- int len;
- unsigned int ipaddr;
-
- if ( memcmp( rawpkt, tribes_master_response, sizeof(tribes_master_response)) != 0) {
- fprintf( stderr, "Odd packet from Tribes master server\n");
- print_packet( server, rawpkt, pktlen);
- }
-
- /* 0x1006
- 01 packet number
- 08 # packets
- 02
- 0000
- 66
- 0d length of following string
- "Tribes Master"
- 3c length of following string
- "Check out the Starsiege demo now! www.starsiegeplayers.com"
- 0035
- 06 d143 4764 812c
- 06 d1e2 8df3 616d
- 06 1804 6d50 616d
- 06 d81c 6dc0 616d
- */
- /* 0x1006
- 02
- 08
- 02 0000
- 66
- 00 3f
- 06 cf88 344c 1227
- */
-
- /* printf( "packet_number %d n_packets %d\n", packet_number, n_packets);
- */
-
- len= upkt[8];
- if ( len > 0) {
- p= (unsigned char*) rawpkt+9;
- /* printf( "%.*s\n", len, p);
- */
- p+= len;
- len= upkt[8+len+1];
- /* printf( "%.*s\n", len, p+1);
- */
- p+= len+1;
- p+= 2;
- }
- else
- p= (unsigned char*) rawpkt+10;
-
- if ( server->master_pkt == NULL) {
- server->master_pkt= (char*)malloc( n_packets*64*6);
- mpkt= server->master_pkt;
- }
- else
- mpkt= server->master_pkt + server->n_servers*6;
-
- while ( (char*)p < rawpkt+pktlen) {
- if ( *p != 0x6) printf( "*p %u\n", (unsigned)*p);
- memcpy( mpkt, p+1, sizeof(ipaddr));
- if ( 0) {
- mpkt[4]= p[5];
- mpkt[5]= p[6];
- }
- else {
- mpkt[5]= p[5];
- mpkt[4]= p[6];
- }
- /*
- printf( "%08x:%hu %u.%u.%u.%u:%hu\n", ipaddr, port, ipaddr>>24,
- (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, port);
- */
- p+= 7;
- mpkt+= 6;
- }
- /*
- if ( (char*)p != rawpkt+pktlen)
- printf( "%x %x\n", p, rawpkt+pktlen);
- */
- server->master_pkt_len= mpkt - server->master_pkt;
- server->n_servers= server->master_pkt_len / 6;
- server->server_name= MASTER;
- server->next_player_info= -1;
-
- if ( packet_number >= n_packets)
- cleanup_qserver( server, 1);
- else
- cleanup_qserver( server, 0);
- }
-
- char *
- display_tribes2_string_list( unsigned char *pkt)
- {
- char *delim="";
- unsigned int count, len;
- count= *pkt;
- pkt++;
- for ( ; count; count--) {
- len= *pkt;
- pkt++;
- if ( len > 0) {
- if ( raw_display) {
- fprintf( OF, "%s%.*s", delim, len, pkt);
- delim= raw_delimiter;
- }
- else
- fprintf( OF, "%.*s\n", len, pkt);
- }
- pkt+= len;
- }
- if ( raw_display)
- fputs( "\n", OF);
- return (char*)pkt;
- }
-
- void
- deal_with_tribes2master_packet( struct qserver *server, char *pkt, int pktlen)
- {
- unsigned int n_servers, index, total, server_limit;
- char *p, *mpkt;
-
- if ( pkt[0] == TRIBES2_RESPONSE_GAME_TYPES) {
- pkt+= 6;
- if ( raw_display) {
- fprintf( OF, "%s%s%s%s", server->type->type_prefix, raw_delimiter,
- server->arg, raw_delimiter);
- }
- else {
- fprintf( OF, "Game Types\n");
- fprintf( OF, "----------\n");
- }
- pkt= display_tribes2_string_list( (unsigned char *)pkt);
- if ( raw_display) {
- fprintf( OF, "%s%s%s%s", server->type->type_prefix, raw_delimiter,
- server->arg, raw_delimiter);
- }
- else {
- fprintf( OF, "\nMission Types\n");
- fprintf( OF, "-------------\n");
- }
- display_tribes2_string_list( (unsigned char *)pkt);
-
- server->master_pkt_len= 0;
- server->n_servers= 0;
- server->server_name= MASTER;
- server->next_player_info= -1;
- cleanup_qserver( server, 1);
- return;
- }
-
- if ( pkt[0] != TRIBES2_RESPONSE_MASTER) {
- /* error */
- cleanup_qserver( server, 1);
- }
-
- server_limit= get_param_ui_value( server, "limit", ~0);
-
- n_servers= little_endian ? *(unsigned short*)(pkt+8) :
- swap_short(pkt+8);
- index= *(unsigned char*)(pkt+6);
- total= *(unsigned char*)(pkt+7);
- if ( server->master_pkt == NULL) {
- server->master_pkt= (char*)malloc( total * n_servers * 6);
- mpkt= server->master_pkt;
- }
- else
- mpkt= server->master_pkt + server->n_servers*6;
-
- p= pkt+10;
- for ( ; n_servers && ((char*)mpkt - server->master_pkt)/6 < server_limit;
- n_servers--, p+= 6, mpkt+= 6) {
- memcpy( mpkt, p, 4);
- mpkt[4]= p[5];
- mpkt[5]= p[4];
- }
- server->master_pkt_len= (char*)mpkt - server->master_pkt;
- server->n_servers= server->master_pkt_len / 6;
- server->server_name= MASTER;
- server->next_player_info= -1;
-
- if ( index >= total-1 || server->n_servers >= server_limit)
- cleanup_qserver( server, 1);
- else
- cleanup_qserver( server, 0);
- }
-
- int
- server_info_packet( struct qserver *server, struct q_packet *pkt, int datalen)
- {
- int off= 0;
-
- /* ignore duplicate packets */
- if ( server->server_name != NULL)
- return 0;
-
- server->address= strdup((char*)&pkt->data[off]);
- off+= strlen(server->address) + 1;
- if ( off >= datalen)
- return -1;
-
- server->server_name= strdup((char*)&pkt->data[off]);
- off+= strlen(server->server_name) + 1;
- if ( off >= datalen)
- return -1;
-
- server->map_name= strdup((char*)&pkt->data[off]);
- off+= strlen(server->map_name) + 1;
- if ( off > datalen)
- return -1;
-
- server->num_players= pkt->data[off++];
- server->max_players= pkt->data[off++];
- server->protocol_version= pkt->data[off++];
-
- server->retry1= n_retries;
-
- if ( get_server_rules)
- send_rule_request_packet( server);
- if ( get_player_info)
- send_player_request_packet( server);
-
- return 0;
- }
-
- int
- player_info_packet( struct qserver *server, struct q_packet *pkt, int datalen)
- {
- char *name, *address;
- int off, colors, frags, connect_time, player_number;
- struct player *player, *last;
-
- off= 0;
- player_number= pkt->data[off++];
- name= (char*) &pkt->data[off];
- off+= strlen(name)+1;
- if ( off >= datalen)
- return -1;
-
- colors= pkt->data[off+3];
- colors= (colors<<8) + pkt->data[off+2];
- colors= (colors<<8) + pkt->data[off+1];
- colors= (colors<<8) + pkt->data[off];
- off+= sizeof(colors);
-
- frags= pkt->data[off+3];
- frags= (frags<<8) + pkt->data[off+2];
- frags= (frags<<8) + pkt->data[off+1];
- frags= (frags<<8) + pkt->data[off];
- off+= sizeof(frags);
-
- connect_time= pkt->data[off+3];
- connect_time= (connect_time<<8) + pkt->data[off+2];
- connect_time= (connect_time<<8) + pkt->data[off+1];
- connect_time= (connect_time<<8) + pkt->data[off];
- off+= sizeof(connect_time);
-
- address= (char*) &pkt->data[off];
- off+= strlen(address)+1;
- if ( off > datalen)
- return -1;
-
- last= server->players;
- while ( last != NULL && last->next != NULL) {
- if ( last->number == player_number)
- return 0;
- last= last->next;
- }
- if ( last != NULL && last->number == player_number)
- return 0;
-
- player= (struct player *) calloc( 1, sizeof(struct player));
- player->number= player_number;
- player->name= strdup( name);
- player->address= strdup( address);
- player->connect_time= connect_time;
- player->frags= frags;
- player->shirt_color= colors>>4;
- player->pants_color= colors&0xf;
- player->next= NULL;
-
- if ( last == NULL)
- server->players= player;
- else
- last->next= player;
-
- server->next_player_info++;
- server->retry2= n_retries;
- if ( server->next_player_info < server->num_players)
- send_player_request_packet( server);
-
- return 0;
- }
-
- int
- rule_info_packet( struct qserver *server, struct q_packet *pkt, int datalen)
- {
- int off= 0;
- struct rule *rule, *last;
- char *name, *value;
-
- /* Straggler packet after we've already given up fetching rules */
- if ( server->next_rule == NULL)
- return 0;
-
- if ( ntohs(pkt->length) == Q_HEADER_LEN) {
- server->next_rule= NULL;
- return 0;
- }
-
- name= (char*)&pkt->data[off];
- off+= strlen( name)+1;
- if ( off >= datalen)
- return -1;
-
- value= (char*)&pkt->data[off];
- off+= strlen( value)+1;
- if ( off > datalen)
- return -1;
-
- last= server->rules;
- while ( last != NULL && last->next != NULL) {
- if ( strcmp( last->name, name) == 0)
- return 0;
- last= last->next;
- }
- if ( last != NULL && strcmp( last->name, name) == 0)
- return 0;
-
- rule= (struct rule *) malloc( sizeof( struct rule));
- rule->name= strdup( name);
- rule->value= strdup( value);
- rule->next= NULL;
-
- if ( last == NULL)
- server->rules= rule;
- else
- last->next= rule;
-
- server->n_rules++;
- server->next_rule= rule->name;
- server->retry1= n_retries;
- send_rule_request_packet( server);
-
- return 0;
- }
-
- struct rule *
- add_rule( struct qserver *server, char *key, char *value, int flags)
- {
- struct rule *rule;
- if ( flags & CHECK_DUPLICATE_RULES) {
- for ( rule= server->rules; rule; rule= rule->next)
- if ( strcmp( rule->name, key) == 0)
- return rule;
- }
-
- rule= (struct rule *) malloc( sizeof( struct rule));
- rule->name= strdup(key);
- if ( flags & NO_VALUE_COPY)
- rule->value= value;
- else
- rule->value= strdup(value);
- rule->next= NULL;
- *server->last_rule= rule;
- server->last_rule= & rule->next;
- server->n_rules++;
- return rule;
- }
-
- void
- add_nrule( struct qserver *server, char *key, char *value, int len)
- {
- struct rule *rule;
- for ( rule= server->rules; rule; rule= rule->next)
- if ( strcmp( rule->name, key) == 0)
- return;
-
- rule= (struct rule *) malloc( sizeof( struct rule));
- rule->name= strdup(key);
- rule->value= strndup(value,len);
- rule->next= NULL;
- *server->last_rule= rule;
- server->last_rule= & rule->next;
- server->n_rules++;
- }
-
- struct player *
- add_player( struct qserver *server, int player_number)
- {
- struct player *player;
- for ( player= server->players; player; player= player->next)
- if ( player->number == player_number)
- return NULL;
-
- player= (struct player *) calloc( 1, sizeof( struct player));
- player->number= player_number;
- player->next= server->players;
- server->players= player;
- return player;
- }
-
- void
- deal_with_unreal_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- char *s, *key, *value, *end;
- struct player *player= NULL;
- int id_major, id_minor, final=0;
-
- server->n_servers++;
- if ( server->server_name == NULL)
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time1);
- else
- gettimeofday( &server->packet_time1, NULL);
-
- rawpkt[pktlen]= '\0';
- end= &rawpkt[pktlen];
-
- s= rawpkt;
- while ( *s) {
- while ( *s == '\\') s++;
- if ( !*s) break;
- key= s;
- while ( *s && *s != '\\') s++;
- if ( !*s) break;
- *s++= '\0';
-
- /*
- while ( *s == '\\') s++;
- if ( !*s)
- value= NULL;
- else
- value= s;
- */
- value= s;
- while ( *s && *s != '\\') s++;
- if ( s[1] && !isalpha(s[1])) {
- s++;
- while ( *s && *s != '\\') s++;
- }
- else if ( s[1] && isalpha(s[1]) &&
- strncmp( key, "player_", 7) == 0) {
- if ( ! unreal_player_info_key( s+1, end)) {
- s++;
- while ( *s && *s != '\\') s++;
- }
- }
- if ( *s)
- *s++= '\0';
-
- if ( *value == '\0') {
- if ( strcmp( key, "final") == 0) {
- final= 1;
- continue;
- }
- }
-
- if ( strcmp( key, "mapname") == 0 && !server->map_name)
- server->map_name= strdup( value);
- else if ( strcmp( key, "hostname") == 0 && !server->server_name)
- server->server_name= strdup( value);
- else if ( strcmp( key, "maxplayers") == 0)
- server->max_players= atoi( value);
- else if ( strcmp( key, "numplayers") == 0)
- server->num_players= atoi( value);
- else if ( strcmp( key, server->type->game_rule) == 0 && !server->game) {
- server->game= strdup( value);
- add_rule( server, key, value, NO_FLAGS);
- }
- else if ( strcmp( key, "queryid") == 0)
- sscanf( value, "%d.%d", &id_major, &id_minor);
- else if ( strcmp( key, "final") == 0) {
- final= 1;
- continue;
- }
- else if ( strncmp( key, "player_", 7) == 0) {
- player= add_player( server, atoi(key+7));
- if ( player)
- player->name= strdup( value);
- }
- else if ( player && strncmp( key, "frags_", 6) == 0)
- player->frags= atoi( value);
- else if ( player && strncmp( key, "team_", 5) == 0)
- player->team= atoi( value);
- else if ( player && strncmp( key, "skin_", 5) == 0)
- player->skin= strdup( value);
- else if ( player && strncmp( key, "mesh_", 5) == 0)
- player->mesh= strdup( value);
- else if ( player && strncmp( key, "ping_", 5) == 0)
- player->ping= atoi( value);
- else if ( player && strncmp( key, "face_", 5) == 0)
- player->face= strdup( value);
- else if ( player && strncmp( key, "deaths_", 7) == 0)
- player->deaths= atoi( value);
- else {
- player= NULL;
- add_rule( server, key, value, NO_FLAGS);
- }
- }
-
- if ( final)
- cleanup_qserver( server, 1);
- if ( server->num_players < 0 && id_minor >= 3)
- cleanup_qserver( server, 1);
- }
-
- STATIC int
- unreal_player_info_key( char *s, char *end)
- {
- static char *keys[] = {"frags_", "team_", "ping_", "species_"};
- int i;
-
- for ( i= 0; i < sizeof(keys)/sizeof(char*); i++) {
- int len= strlen(keys[i]);
- if ( s+len < end && strncmp( s, keys[i], len) == 0)
- return 1;
- }
- return 0;
- }
-
- int
- deal_with_unrealmaster_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- if ( pktlen == 0) {
- cleanup_qserver( server, 1);
- return 0;
- }
- print_packet( server, rawpkt, pktlen);
- puts( "--");
- return 0;
- }
-
- void
- deal_with_halflife_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- char *pkt;
- char *end= &rawpkt[pktlen];
- int pkt_index= 0, pkt_max= 0;
- char number[16];
- short pkt_id;
-
- if ( server->server_name == NULL)
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time1);
-
- if ( pktlen < 5) {
- cleanup_qserver( server, 1);
- return;
- }
-
- if ( ((rawpkt[0] != '\377' && rawpkt[0] != '\376') || rawpkt[1] != '\377' ||
- rawpkt[2] != '\377' || rawpkt[3] != '\377') && show_errors) {
- unsigned int ipaddr= ntohl(server->ipaddr);
- fprintf( stderr,
- "Odd packet from server %d.%d.%d.%d:%hu, processing ...\n",
- (ipaddr>>24)&0xff, (ipaddr>>16)&0xff,
- (ipaddr>>8)&0xff, ipaddr&0xff, ntohs(server->port));
- print_packet( server, rawpkt, pktlen);
- }
-
- if ( ((unsigned char*)rawpkt)[0] == 0xfe) {
- SavedData *sdata;
- pkt_index= ((unsigned char*)rawpkt)[8] >> 4;
- pkt_max= ((unsigned char*)rawpkt)[8] & 0xf;
- memcpy( &pkt_id, &rawpkt[4], 2);
-
- if ( server->saved_data.data == NULL)
- sdata= & server->saved_data;
- else {
- sdata= (SavedData*) calloc( 1, sizeof(SavedData));
- sdata->next= server->saved_data.next;
- server->saved_data.next= sdata;
- }
-
- sdata->pkt_index= pkt_index;
- sdata->pkt_max= pkt_max;
- sdata->pkt_id= pkt_id;
- sdata->datalen= pktlen-9;
- sdata->data= (char*) malloc( pktlen-9);
- memcpy( sdata->data, &rawpkt[9], pktlen-9);
-
- /* combine_packets will call us recursively */
- combine_packets( server);
- return;
-
- /*
- fprintf( OF, "pkt_index %d pkt_max %d\n", pkt_index, pkt_max);
- rawpkt+= 9;
- pktlen-= 9;
- */
- }
-
- /* 'info' response */
- if ( rawpkt[4] == 'C' || rawpkt[4] == 'm') {
- if ( server->server_name != NULL)
- return;
- pkt= &rawpkt[5];
- server->address= strdup( pkt);
- pkt+= strlen(pkt)+1;
- server->server_name= strdup( pkt);
- pkt+= strlen(pkt)+1;
- server->map_name= strdup( pkt);
- pkt+= strlen(pkt)+1;
-
- if ( *pkt)
- add_rule( server, "gamedir", pkt, NO_FLAGS);
- if ( *pkt && strcmp( pkt, "valve") != 0)
- server->game= add_rule( server, "game", pkt, NO_FLAGS)->value;
- pkt+= strlen(pkt)+1;
- if ( *pkt)
- add_rule( server, "gamename", pkt, NO_FLAGS);
- pkt+= strlen(pkt)+1;
-
- server->num_players= (unsigned int)pkt[0];
- server->max_players= (unsigned int)pkt[1];
- pkt+= 2;
- if ( pkt < end) {
- int protocol= *((unsigned char *)pkt);
- sprintf( number, "%d", protocol);
- add_rule( server, "protocol", number, NO_FLAGS);
- pkt++;
- }
-
- if ( rawpkt[4] == 'm') {
- if ( *pkt == 'd')
- add_rule( server, "sv_type", "dedicated", NO_FLAGS);
- else if ( *pkt == 'l')
- add_rule( server, "sv_type", "listen", NO_FLAGS);
- else
- add_rule( server, "sv_type", "?", NO_FLAGS);
- pkt++;
- if ( *pkt == 'w')
- add_rule( server, "sv_os", "windows", NO_FLAGS);
- else if ( *pkt == 'l')
- add_rule( server, "sv_os", "linux", NO_FLAGS);
- else {
- char str[2]= "\0";
- str[0]= *pkt;
- add_rule( server, "sv_os", str, NO_FLAGS);
- }
- pkt++;
- add_rule( server, "sv_password", *pkt ? "1" : "0", NO_FLAGS);
- pkt++;
- add_rule( server, "mod", *pkt ? "1" : "0", NO_FLAGS);
- if ( *pkt) {
- int n;
- /* pull out the mod infomation */
- pkt++;
- add_rule( server, "mod_info_url", pkt, NO_FLAGS);
- pkt+= strlen( pkt)+1;
- if ( *pkt)
- add_rule( server, "mod_download_url", pkt, NO_FLAGS);
- pkt+= strlen( pkt)+1;
- if ( *pkt)
- add_rule( server, "mod_detail", pkt, NO_FLAGS);
- pkt+= strlen( pkt)+1;
- n= swap_long_from_little( pkt);
- sprintf( number, "%d", n);
- add_rule( server, "modversion", number, NO_FLAGS);
- pkt+= 4;
- n= swap_long_from_little( pkt);
- sprintf( number, "%d", n);
- add_rule( server, "modsize", number, NO_FLAGS);
- pkt+= 4;
- add_rule( server, "svonly", *pkt ? "1" : "0", NO_FLAGS);
- pkt++;
- add_rule( server, "cldll", *pkt ? "1" : "0", NO_FLAGS);
- pkt++;
- if ( pkt < end)
- add_rule( server, "secure", *pkt ? "1" : "0", NO_FLAGS);
- }
- }
-
- if ( get_player_info && server->num_players) {
- server->next_player_info= server->num_players-1;
- send_player_request_packet( server);
- }
- if ( get_server_rules) {
- server->next_rule= "";
- server->retry1= n_retries;
- send_rule_request_packet( server);
- }
- }
- /* 'players' response */
- else if ( rawpkt[4] == 'D' && server->players == NULL) {
- unsigned int n= 0, temp;
- float *ingame= (float*) &temp;
- struct player *player;
- struct player **last_player= & server->players;
- if ( (unsigned int)rawpkt[5] > server->num_players)
- server->num_players= (unsigned int)rawpkt[5];
- pkt= &rawpkt[6];
- rawpkt[pktlen]= '\0';
- while (1) {
- if ( *pkt != n+1)
- break;
- n++;
- pkt++;
- player= (struct player*) calloc( 1, sizeof(struct player));
- player->name= strdup( pkt);
- pkt+= strlen(pkt)+1;
- memcpy( &player->frags, pkt, 4);
- pkt+= 4;
- memcpy( &temp, pkt, 4);
- pkt+= 4;
- if ( big_endian) {
- player->frags= swap_long( &player->frags);
- temp= swap_long( &temp);
- }
- player->connect_time= *ingame;
- *last_player= player;
- last_player= & player->next;
- }
- if ( n > server->num_players)
- server->num_players= n;
- server->next_player_info= server->num_players;
- }
- /* 'rules' response */
- else if ( rawpkt[4] == 'E' && server->next_rule != NULL) {
- int n= 0;
- struct rule *rule;
- n= ((unsigned char*)rawpkt)[5] + ((unsigned char *)rawpkt)[6]*256;
- pkt= &rawpkt[7];
- while ( n) {
- char *key= pkt;
- char *value;
- pkt+= strlen(pkt)+1;
- if ( pkt > end)
- break;
- value= pkt;
- pkt+= strlen(pkt)+1;
- if ( pkt > end)
- break;
- add_rule( server, key, value, NO_FLAGS);
- n--;
- }
- server->next_rule= NULL;
- }
- else if ( rawpkt[4] != 'E' && rawpkt[4] != 'D' && rawpkt[4] != 'm' &&
- rawpkt[4] != 'C' && show_errors) {
- /* if ( pkt_count) { rawpkt-= 9; pktlen+= 9; } */
- fprintf( stderr, "Odd packet from HL server %s (packet len %d)\n",
- server->arg, pktlen);
- print_packet( server, rawpkt, pktlen);
- }
-
- cleanup_qserver( server, 0);
- }
-
-
- int
- combine_packets( struct qserver *server)
- {
- unsigned int ids[8];
- int maxes[8];
- int counts[8];
- int lengths[8];
- SavedData * segments[8][16];
- SavedData *sdata= & server->saved_data;
- int n_ids= 0, i, p;
-
- memset( &segments[0][0], 0, sizeof(segments));
- memset( &counts[0], 0, sizeof(counts));
- memset( &lengths[0], 0, sizeof(lengths));
-
- for ( ; sdata != NULL; sdata= sdata->next) {
- if ( sdata->pkt_max == 0)
- continue;
- for (i= 0; i < n_ids; i++)
- if ( sdata->pkt_id == ids[i])
- break;
- if ( i >= n_ids) {
- if ( n_ids >= 8)
- continue;
- ids[n_ids]= sdata->pkt_id;
- maxes[n_ids]= sdata->pkt_max;
- i= n_ids++;
- }
- else if ( maxes[i] != sdata->pkt_max)
- continue;
- if ( segments[i][sdata->pkt_index] == NULL) {
- segments[i][sdata->pkt_index]= sdata;
- counts[i]++;
- lengths[i]+= sdata->datalen;
- }
- }
-
- for ( i= 0; i < n_ids; i++) {
- char *combined;
- int datalen= 0;
- if ( counts[i] != maxes[i])
- continue;
-
- combined= (char*)malloc( lengths[i]);
- for ( p= 0; p < counts[i]; p++) {
- if ( segments[i][p] == NULL)
- break;
- memcpy( combined + datalen, segments[i][p]->data,
- segments[i][p]->datalen);
- datalen+= segments[i][p]->datalen;
- }
- if ( p < counts[i]) {
- free( combined);
- continue;
- }
-
- for ( p= 0; p < counts[i]; p++)
- segments[i][p]->pkt_max= 0;
-
- server->type->packet_func( server, combined, datalen);
- free( combined);
- if ( server->saved_data.data == NULL)
- break;
- }
- return 0;
- }
-
- static int tribes_debug= 0;
-
- void
- deal_with_tribes_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- unsigned char *pkt, *end;
- int len, pnum, ping, packet_loss, n_teams, t;
- struct player *player;
- struct player **teams= NULL;
- struct player **last_player= & server->players;
- char buf[24];
-
- if ( server->server_name == NULL)
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time1);
- else
- gettimeofday( &server->packet_time1, NULL);
-
- if ( pktlen < sizeof( tribes_info_reponse)) {
- cleanup_qserver( server, 1);
- return;
- }
- if ( get_player_info || get_server_rules) {
- if ( strncmp( rawpkt, tribes_players_reponse,
- sizeof( tribes_players_reponse)) != 0) {
- cleanup_qserver( server, 1);
- return;
- }
- }
- else if ( strncmp( rawpkt, tribes_info_reponse,
- sizeof( tribes_info_reponse)) != 0) {
- cleanup_qserver( server, 1);
- return;
- }
-
- pkt= (unsigned char*) &rawpkt[sizeof( tribes_info_reponse)];
-
- len= *pkt; /* game name: "Tribes" */
- add_nrule( server, "gamename", (char*)pkt+1, len);
- pkt+= len+1;
- len= *pkt; /* version */
- add_nrule( server, "version", (char*)pkt+1, len);
- pkt+= len+1;
- len= *pkt; /* server name */
- server->server_name= strndup( (char*)pkt+1, len);
- pkt+= len+1;
- add_rule( server, "dedicated", *pkt?"1":"0", NO_FLAGS);
- pkt++; /* flag: dedicated server */
- add_rule( server, "needpass", *pkt?"1":"0", NO_FLAGS);
- pkt++; /* flag: password on server */
- server->num_players= *pkt++;
- server->max_players= *pkt++;
-
- if ( !get_player_info && !get_server_rules) {
- cleanup_qserver( server, 0);
- return;
- }
-
- sprintf( buf, "%u", (unsigned int)pkt[0] + (unsigned int)pkt[1]*256);
- add_rule( server, "cpu", buf, NO_FLAGS);
- pkt++; /* cpu speed, lsb */
- pkt++; /* cpu speed, msb */
-
- len= *pkt; /* Mod (game) */
- add_nrule( server, "mods", (char*)pkt+1, len);
- pkt+= len+1;
-
- len= *pkt; /* game (mission): "C&H" */
- add_nrule( server, "game", (char*)pkt+1, len);
- pkt+= len+1;
-
- len= *pkt; /* Mission (map) */
- server->map_name= strndup( (char*)pkt+1, len);
- pkt+= len+1;
-
- len= *pkt; /* description (contains Admin: and Email: ) */
- if ( tribes_debug) printf( "%.*s\n", len, pkt+1);
- pkt+= len+1;
-
- n_teams= *pkt++; /* number of teams */
- if ( n_teams == 255) {
- cleanup_qserver( server, 1);
- return;
- }
- sprintf( buf, "%d", n_teams);
- add_rule( server, "numteams", buf, NO_FLAGS);
-
- len= *pkt; /* first title */
- if ( tribes_debug) printf( "%.*s\n", len, pkt+1);
- pkt+= len+1;
-
- len= *pkt; /* second title */
- if ( tribes_debug) printf( "%.*s\n", len, pkt+1);
- pkt+= len+1;
-
- if ( n_teams > 1) {
- teams= (struct player**) calloc( 1, sizeof(struct player*) * n_teams);
- for ( t= 0; t < n_teams; t++) {
- teams[t]= (struct player*) calloc(1, sizeof(struct player));
- teams[t]->number= TRIBES_TEAM;
- teams[t]->team= t;
- len= *pkt; /* team name */
- teams[t]->name= strndup( (char*)pkt+1, len);
- if ( tribes_debug) printf( "team#0 <%.*s>\n", len, pkt+1);
- pkt+= len+1;
-
- len= *pkt; /* team score */
- if ( len <= 2 && tribes_debug) printf( "%s score len %d\n", server->arg, len);
- if ( len > 2) {
- strncpy( buf, (char*)pkt+1+3, len-3);
- buf[len-3]= '\0';
- }
- else
- buf[0]= '\0';
- teams[t]->frags= atoi( buf);
- if ( tribes_debug) printf( "team#0 <%.*s>\n", len-3, pkt+1+3);
- pkt+= len+1;
- }
- }
- else {
- len= *pkt; /* DM team? */
- if ( tribes_debug) printf( "%.*s\n", len, pkt+1);
- pkt+= len+1;
- pkt++;
- n_teams= 0;
- }
-
- pnum= 0;
- while ( (char*)pkt < (rawpkt+pktlen)) {
- ping= (unsigned int)*pkt << 2;
- pkt++;
- packet_loss= *pkt;
- pkt++;
- if ( tribes_debug) printf( "player#%d, team #%d\n", pnum, (int)*pkt);
- pkt++;
- len= *pkt;
- if ( (char*)pkt+len > (rawpkt+pktlen))
- break;
- player= (struct player*) calloc( 1, sizeof(struct player));
- player->team= pkt[-1];
- if ( n_teams && player->team < n_teams)
- player->team_name= teams[player->team]->name;
- else if ( player->team == 255 && n_teams)
- player->team_name= "Unknown";
- player->ping= ping;
- player->packet_loss= packet_loss;
- player->name= strndup( (char*)pkt+1, len);
- if ( tribes_debug) printf( "player#%d, name %.*s\n", pnum, len, pkt+1);
- pkt+= len+1;
- len= *pkt;
- if ( tribes_debug) printf( "player#%d, info <%.*s>\n", pnum, len, pkt+1);
- end= (unsigned char*) strchr( (char*)pkt+9, 0x9);
- if ( end) {
- strncpy( buf, (char*)pkt+9, end-(pkt+9));
- buf[end-(pkt+9)]= '\0';
- player->frags= atoi( buf);
- if ( tribes_debug) printf( "player#%d, score <%.*s>\n", pnum, end-(pkt+9), pkt+9);
- }
- *last_player= player;
- last_player= & player->next;
-
- pkt+= len+1;
- pnum++;
- }
-
- for ( t= n_teams; t;) {
- t--;
- teams[t]->next= server->players;
- server->players= teams[t];
- }
- free( teams);
-
- cleanup_qserver( server, 0);
- }
-
- void
- get_tribes2_player_type( struct player *player)
- {
- char *name= player->name;
- for ( ; *name; name++) {
- switch ( *name) {
- case 0x8: player->type_flag= PLAYER_TYPE_NORMAL; continue;
- case 0xc: player->type_flag= PLAYER_TYPE_ALIAS; continue;
- case 0xe: player->type_flag= PLAYER_TYPE_BOT; continue;
- case 0xb: break;
- default: continue;
- }
- name++;
- if ( isprint( *name)) {
- char *n= name;
- for ( ; isprint(*n); n++)
- ;
- player->tribe_tag= strndup( name, n-name);
- name= n;
- }
- if ( !*name)
- break;
- }
- }
-
- void
- deal_with_tribes2_packet( struct qserver *server, char *pkt, int pktlen)
- {
- char str[256], *pktstart= pkt, *term, *start;
- unsigned int minimum_net_protocol, build_version, i, t, len, s, status;
- unsigned int net_protocol;
- unsigned short cpu_speed;
- int n_teams= 0, n_players;
- struct player **teams= NULL, *player;
- struct player **last_player= & server->players;
- int query_version;
-
- pkt[pktlen]= '\0';
-
- if ( server->server_name == NULL)
- server->ping_total+= time_delta( &packet_recv_time,
- &server->packet_time1);
- /*
- else
- gettimeofday( &server->packet_time1, NULL);
- */
-
- if ( pkt[0] == TRIBES2_RESPONSE_PING) {
- if ( pkt[6] < 4 || pkt[6] > 12 || strncmp( pkt+7, "VER", 3) != 0) {
- cleanup_qserver( server, 1);
- return;
- }
- strncpy( str, pkt+10, pkt[6]-3);
- str[ pkt[6]-3]= '\0';
- query_version= atoi( str);
- add_nrule(server,"queryversion", pkt+7, pkt[6]);
- pkt+= 7 + pkt[6];
-
- server->protocol_version= query_version;
- if ( query_version != 3 && query_version != 5) {
- server->server_name= strdup( "Unknown query version");
- cleanup_qserver( server, 1);
- return;
- }
-
- if ( query_version == 5) {
- net_protocol= swap_long_from_little( pkt);
- sprintf( str, "%u", net_protocol);
- add_rule(server,"net_protocol",str, NO_FLAGS);
- pkt+= 4;
- }
- minimum_net_protocol= swap_long_from_little( pkt);
- sprintf( str, "%u", minimum_net_protocol);
- add_rule(server,"minimum_net_protocol",str, NO_FLAGS);
- pkt+= 4;
- build_version= swap_long_from_little( pkt);
- sprintf( str, "%u", build_version);
- add_rule(server,"build_version",str, NO_FLAGS);
- pkt+= 4;
-
- server->server_name= strndup( pkt+1, *(unsigned char*)(pkt));
-
- send( server->fd, server->type->player_packet,
- server->type->status_len, 0);
- return;
- }
- else if ( pkt[0] != TRIBES2_RESPONSE_INFO) {
- cleanup_qserver( server, 1);
- return;
- }
-
- pkt+= 6;
- for ( i= 0; i < *(unsigned char *)pkt; i++)
- if ( !isprint(pkt[i+1])) {
- cleanup_qserver( server, 1);
- return;
- }
- add_nrule( server, server->type->game_rule, pkt+1, *(unsigned char *)pkt);
- server->game= strndup( pkt+1, *(unsigned char *)pkt);
- pkt+= *pkt + 1;
- add_nrule( server, "mission", pkt+1, *(unsigned char *)pkt);
- pkt+= *pkt + 1;
- server->map_name= strndup( pkt+1, *(unsigned char *)pkt);
- pkt+= *pkt + 1;
-
- status= *(unsigned char *)pkt;
- sprintf( str, "%u", status);
- add_rule( server, "status", str, NO_FLAGS);
- if ( status & TRIBES2_STATUS_DEDICATED)
- add_rule( server, "dedicated", "1", NO_FLAGS);
- if ( status & TRIBES2_STATUS_PASSWORD)
- add_rule( server, "password", "1", NO_FLAGS);
- if ( status & TRIBES2_STATUS_LINUX)
- add_rule( server, "linux", "1", NO_FLAGS);
- if ( status & TRIBES2_STATUS_TEAMDAMAGE)
- add_rule( server, "teamdamage", "1", NO_FLAGS);
- if ( server->protocol_version == 3) {
- if ( status & TRIBES2_STATUS_TOURNAMENT_VER3)
- add_rule( server, "tournament", "1", NO_FLAGS);
- if ( status & TRIBES2_STATUS_NOALIAS_VER3)
- add_rule( server, "no_aliases", "1", NO_FLAGS);
- }
- else {
- if ( status & TRIBES2_STATUS_TOURNAMENT)
- add_rule( server, "tournament", "1", NO_FLAGS);
- if ( status & TRIBES2_STATUS_NOALIAS)
- add_rule( server, "no_aliases", "1", NO_FLAGS);
- }
- pkt++;
- server->num_players= *(unsigned char *)pkt;
- pkt++;
- server->max_players= *(unsigned char *)pkt;
- pkt++;
- sprintf( str, "%u", *(unsigned char *)pkt);
- add_rule( server, "bot_count", str, NO_FLAGS);
- pkt++;
- cpu_speed= swap_short_from_little( pkt);
- sprintf( str, "%hu", cpu_speed);
- add_rule( server, "cpu_speed", str, NO_FLAGS);
- pkt+= 2;
-
- if ( strcmp( server->server_name, "VER3") == 0) {
- free( server->server_name);
- server->server_name= strndup( pkt+1, *(unsigned char*)pkt);
- }
- else
- add_nrule( server, "info", pkt+1, *(unsigned char*)pkt);
-
- pkt+= *(unsigned char*)pkt + 1;
- len= swap_short_from_little( pkt);
- pkt+= 2;
- start= pkt;
- if ( len+(pkt-pktstart) > pktlen)
- len-= (len+(pkt-pktstart)) - pktlen;
-
- if ( len == 0 || pkt-pktstart >= pktlen) goto info_done;
-
- term= strchr( pkt, 0xa);
- if ( !term) goto info_done;
- *term= '\0';
- n_teams= atoi( pkt);
- sprintf( str, "%d", n_teams);
- add_rule( server, "numteams", str, NO_FLAGS);
- pkt= term + 1;
-
- if ( pkt-pktstart >= pktlen) goto info_done;
-
- teams= (struct player**) calloc( 1, sizeof(struct player*) * n_teams);
- for ( t= 0; t < n_teams; t++) {
- teams[t]= (struct player*) calloc(1, sizeof(struct player));
- teams[t]->number= TRIBES_TEAM;
- teams[t]->team= t;
- /* team name */
- term= strchr( pkt, 0x9);
- if ( !term) { n_teams= t; goto info_done; }
- teams[t]->name= strndup( pkt, term-pkt);
- pkt= term+1;
- term= strchr( pkt, 0xa);
- if ( !term) { n_teams= t; goto info_done; }
- *term='\0';
- teams[t]->frags= atoi(pkt);
- pkt= term+1;
- if ( pkt-pktstart >= pktlen) goto info_done;
- }
-
- term= strchr( pkt, 0xa);
- if ( !term || term-start >= len) goto info_done;
- *term= '\0';
- n_players= atoi( pkt);
- pkt= term + 1;
-
- for ( i= 0; i < n_players && pkt-start < len; i++) {
- pkt++; /* skip first byte (0x10) */
- if ( pkt-start >= len) break;
- player= (struct player*) calloc( 1, sizeof(struct player));
- term= strchr( pkt, 0x11);
- if ( !term || term-start >= len) {
- free( player);
- break;
- }
- player->name= strndup( pkt, term-pkt);
- get_tribes2_player_type( player);
- pkt= term+1;
- pkt++; /* skip 0x9 */
- if ( pkt-start >= len) break;
- term= strchr( pkt, 0x9);
- if ( !term || term-start >= len) {
- free( player->name);
- free( player);
- break;
- }
- for ( t= 0; t < n_teams; t++) {
- if ( term-pkt == strlen(teams[t]->name) &&
- strncmp( pkt, teams[t]->name, term-pkt) == 0)
- break;
- }
- if ( t == n_teams) {
- player->team= -1;
- player->team_name= "Unassigned";
- }
- else {
- player->team= t;
- player->team_name= teams[t]->name;
- }
- pkt= term+1;
- for ( s= 0; *pkt != 0xa && pkt-start < len; pkt++)
- str[s++]= *pkt;
- str[s]= '\0';
- player->frags= atoi(str);
- if ( *pkt == 0xa)
- pkt++;
-
- *last_player= player;
- last_player= & player->next;
- }
-
- info_done:
- for ( t= n_teams; t;) {
- t--;
- teams[t]->next= server->players;
- server->players= teams[t];
- }
- if ( teams) free( teams);
-
- cleanup_qserver( server, 1);
- return;
- }
-
- /* postions of map name, player name (in player substring), zero-based */
- #define BFRIS_MAP_POS 18
- #define BFRIS_PNAME_POS 11
- void
- deal_with_bfris_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- int i, player_data_pos, nplayers;
- SavedData *sdata;
- unsigned char *saved_data;
- int saved_data_size;
-
- server->ping_total += time_delta( &packet_recv_time,
- &server->packet_time1);
-
- /* add to the data previously saved */
- sdata= & server->saved_data;
- if (! sdata->data)
- sdata->data = (char*)malloc(pktlen);
- else
- sdata->data = (char*)realloc(sdata->data,sdata->datalen + pktlen);
-
- memcpy(sdata->data + sdata->datalen, rawpkt, pktlen);
- sdata->datalen += pktlen;
-
- saved_data= (unsigned char*) sdata->data;
- saved_data_size= sdata->datalen;
-
- /* after we get the server portion of the data, server->game != NULL */
- if (!server->game) {
-
- /* server data goes up to map name */
- if (sdata->datalen <= BFRIS_MAP_POS)
- return;
-
- /* see if map name is complete */
- player_data_pos=0;
- for (i=BFRIS_MAP_POS; i<saved_data_size; i++) {
- if (saved_data[i] == '\0') {
- player_data_pos = i+1;
- /* data must extend beyond map name */
- if (saved_data_size <= player_data_pos)
- return;
- break;
- }
- }
-
- /* did we find beginning of player data? */
- if (!player_data_pos)
- return;
-
- /* now we can go ahead and fill in server data */
- server->map_name = strdup((char*)saved_data + BFRIS_MAP_POS);
- server->max_players = saved_data[12];
- server->protocol_version = saved_data[11];
-
- /* save game type */
- switch (saved_data[13] & 15) {
- case 0: server->game = "FFA"; break;
- case 5: server->game = "Rover"; break;
- case 6: server->game = "Occupation"; break;
- case 7: server->game = "SPAAL"; break;
- case 8: server->game = "CTF"; break;
- default:
- server->game = "unknown"; break;
- }
- add_rule(server,server->type->game_rule,server->game, NO_FLAGS);
-
- if (get_server_rules) {
- char buf[24];
-
- /* server revision */
- sprintf(buf,"%d",(unsigned int)saved_data[11]);
- add_rule(server,"Revision",buf, NO_FLAGS);
-
- /* latency */
- sprintf(buf,"%d",(unsigned int)saved_data[10]);
- add_rule(server,"Latency",buf, NO_FLAGS);
-
- /* player allocation */
- add_rule(server,"Allocation",saved_data[13] & 16 ? "Automatic" : "Manual", NO_FLAGS);
-
- }
-
- }
-
- /* If we got this far, we know the data saved goes at least to the start of
- the player information, and that the server data is taken care of.
- */
-
- /* start of player data */
- player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data+BFRIS_MAP_POS) + 1;
-
- /* ensure all player data have arrived */
- nplayers = 0;
- while (saved_data[player_data_pos] != '\0') {
-
- player_data_pos += BFRIS_PNAME_POS;
-
- /* does player data extend to player name? */
- if (saved_data_size <= player_data_pos + 1)
- return;
-
- /* does player data extend to end of player name? */
- for (i=0; player_data_pos + i < saved_data_size; i++) {
-
- if (saved_data_size == player_data_pos + i + 1)
- return;
-
- if (saved_data[player_data_pos + i] == '\0') {
- player_data_pos += i + 1;
- nplayers++;
- break;
- }
- }
- }
- /* all player data are complete */
-
- server->num_players = nplayers;
-
- if (get_player_info) {
-
- /* start of player data */
- player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data+BFRIS_MAP_POS) + 1;
-
- for (i=0; i<nplayers; i++) {
- struct player *player;
- player= add_player( server, saved_data[player_data_pos]);
-
- player->ship = saved_data[player_data_pos + 1];
- player->ping = saved_data[player_data_pos + 2];
- player->frags = saved_data[player_data_pos + 3];
- player->team = saved_data[player_data_pos + 4];
- switch (player->team) {
- case 0: player->team_name = "silver"; break;
- case 1: player->team_name = "red"; break;
- case 2: player->team_name = "blue"; break;
- case 3: player->team_name = "green"; break;
- case 4: player->team_name = "purple"; break;
- case 5: player->team_name = "yellow"; break;
- case 6: player->team_name = "cyan"; break;
- default:
- player->team_name = "unknown"; break;
- }
- player->room = saved_data[player_data_pos + 5];
-
- /* score is little-endian integer */
- player->score =
- saved_data[player_data_pos+7] +
- (saved_data[player_data_pos+8] << 8) +
- (saved_data[player_data_pos+9] << 16) +
- (saved_data[player_data_pos+10] << 24);
-
- /* for archs with > 4-byte int */
- if (player->score & 0x80000000)
- player->score = -(~(player->score)) - 1;
-
-
- player_data_pos += BFRIS_PNAME_POS;
- player->name = strdup((char*)saved_data + player_data_pos);
-
- player_data_pos += strlen(player->name) + 1;
- }
-
- }
-
- server->server_name = "BFRIS Server";
- cleanup_qserver(server, 1);
- return;
- }
-
- struct rule *
- add_uchar_rule( struct qserver *server, char *key, unsigned char value)
- {
- char buf[24];
- sprintf( buf, "%u", (unsigned)value);
- return add_rule( server, key, buf, NO_FLAGS);
- }
-
- void
- deal_with_descent3_packet( struct qserver *server, char *rawpkt, int pktlen)
- {
- char *pkt;
- char buf[24];
-
- if ( server->server_name == NULL)
- server->ping_total += time_delta( &packet_recv_time,
- &server->packet_time1);
-
- if ( pktlen < 4) {
- fprintf( stderr, "short d3 packet\n");
- print_packet( server, rawpkt, pktlen);
- cleanup_qserver( server, 1);
- return;
- }
-
- /* 'info' response */
- if ( rawpkt[1] == 0x1f) {
- if ( server->server_name != NULL)
- {
- cleanup_qserver( server, 1);
- return;
- }
-
-
- pkt= &rawpkt[0x15];
- server->server_name= strdup( pkt);
- pkt+= strlen(pkt)+2;
- server->map_name= strdup( pkt); /* mission name (blah.mn3) */
- pkt+= strlen(pkt)+2;
- add_rule( server, "level_name", pkt, NO_FLAGS);
- pkt+= strlen(pkt)+2;
- add_rule( server, "gametype", pkt, NO_FLAGS);
- pkt+= strlen(pkt)+1;
-
- sprintf( buf, "%hu", swap_short_from_little(pkt));
- add_rule( server, "level_num", buf, NO_FLAGS);
- pkt+=2;
- server->num_players= swap_short_from_little(pkt);
- pkt+=2;
- server->max_players= swap_short_from_little(pkt);
- pkt+=2;
-
- /* unknown/undecoded fields.. stuff like permissible, banned items/ships, etc */
- add_uchar_rule( server, "u0", pkt[0]);
- add_uchar_rule( server, "u1", pkt[1]);
- add_uchar_rule( server, "u2", pkt[2]);
- add_uchar_rule( server, "u3", pkt[3]);
- add_uchar_rule( server, "u4", pkt[4]);
- add_uchar_rule( server, "u5", pkt[5]);
- add_uchar_rule( server, "u6", pkt[6]);
- add_uchar_rule( server, "u7", pkt[7]);
- add_uchar_rule( server, "u8", pkt[8]);
-
- add_uchar_rule( server, "randpowerup", !(pkt[4]&1)); /* randomize powerup spawn */
- add_uchar_rule( server, "acccollisions", (pkt[5]&4) > 0); /* accurate collision detection */
- add_uchar_rule( server, "brightships", (pkt[5]&16) > 0); /* bright player ships */
- add_uchar_rule( server, "mouselook", (pkt[6]&1) > 0); /* mouselook enabled */
- sprintf( buf, "%s%s", (pkt[4]&16)?"PP":"CS", (pkt[6]&1)?"-ML":"");
- add_rule( server, "servertype", buf, NO_FLAGS);
-
- sprintf( buf, "%hhu", pkt[9]);
- add_rule( server, "difficulty", buf, NO_FLAGS);
-
- /* unknown/undecoded fields after known flags removed */
- add_uchar_rule( server, "x4", pkt[4] & ~(1+16));
- add_uchar_rule( server, "x5", pkt[5] & ~(4+16));
- add_uchar_rule( server, "x6", pkt[6] & ~1);
-
- if ( get_player_info && server->num_players) {
- server->next_player_info= 0;
- send_player_request_packet( server);
- cleanup_qserver( server, 0);
- return;
- }
-
- }
- /* MP_PLAYERLIST_DATA */
- else if ( rawpkt[1] == 0x73) {
- struct player *player;
- struct player **last_player= & server->players;
-
- if ( server->players != NULL)
- {
- cleanup_qserver( server, 1);
- return;
- }
-
- pkt= &rawpkt[0x4];
- while (*pkt) {
- player= (struct player*) calloc( 1, sizeof(struct player));
- player->name= strdup( pkt);
- pkt+= strlen(pkt) + 1;
- *last_player= player;
- last_player= & player->next;
- }
- server->next_player_info= NO_PLAYER_INFO;
- }
- else {
- fprintf( stderr, "unknown d3 packet\n");
- print_packet( server, rawpkt, pktlen);
- }
- cleanup_qserver( server, 1);
- return;
- }
-
-
- void
- deal_with_gamespy_master_response( struct qserver *server, char *rawpkt, int pktlen)
- {
- if ( pktlen == 0) {
- int len= server->saved_data.datalen;
- char *data= server->saved_data.data;
- char *ip, *portstr;
- unsigned int ipaddr;
- unsigned short port;
- int master_pkt_max;
-
- server->server_name= "Gamespy Master";
-
- master_pkt_max= (len / 20) * 6;
- server->master_pkt= (char*) malloc( master_pkt_max);
- server->master_pkt_len= 0;
-
- while ( len) {
- for ( ; len && *data == '\\'; data++, len--) ;
- if ( len < 3) break;
- if ( data[0] == 'i' && data[1] == 'p' && data[2] == '\\') {
- data+= 3;
- len-= 3;
- ip= data;
- portstr= NULL;
- for ( ; len && *data != '\\'; data++, len--) {
- if ( *data == ':') {
- portstr= data+1;
- *data= '\0';
- }
- }
- if ( len == 0)
- break;
- *data++= '\0';
- len--;
- ipaddr= inet_addr( ip);
- if ( portstr)
- port= htons( (unsigned short)atoi( portstr));
- else
- port= htons( 28000); /* ## default port */
- if ( server->master_pkt_len >= master_pkt_max) {
- master_pkt_max+= 20*6;
- server->master_pkt= (char*) realloc( server->master_pkt,
- master_pkt_max);
- }
- memcpy( server->master_pkt + server->master_pkt_len,
- &ipaddr, 4);
- memcpy( server->master_pkt + server->master_pkt_len + 4,
- &port, 2);
- server->master_pkt_len+= 6;
- }
- else
- for ( ; len && *data != '\\'; data++, len--) ;
- }
-
- server->n_servers= server->master_pkt_len / 6;
- server->next_player_info= -1;
- server->retry1= 0;
-
- cleanup_qserver( server, 1);
- return;
- }
-
- if (! server->saved_data.data)
- server->saved_data.data= (char*)malloc( pktlen);
- else
- server->saved_data.data= (char*)realloc( server->saved_data.data,
- server->saved_data.datalen + pktlen);
-
- memcpy( server->saved_data.data + server->saved_data.datalen, rawpkt, pktlen);
- server->saved_data.datalen+= pktlen;
-
- }
-
- /* Misc utility functions
- */
-
- char *
- strndup( char *string, int len)
- {
- char *result;
- result= (char*) malloc( len+1);
- memcpy( result, string, len);
- result[len]= '\0';
- return result;
- }
-
- unsigned int
- swap_long( void *l)
- {
- unsigned char *b= (unsigned char *) l;
- return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
- }
-
- unsigned short
- swap_short( void *l)
- {
- unsigned char *b= (unsigned char *) l;
- return (unsigned short)b[0] | (b[1]<<8);
- }
-
- unsigned int
- swap_long_from_little( void *l)
- {
- unsigned char *b= (unsigned char *) l;
- unsigned int result;
- if ( little_endian)
- memcpy( &result, l, 4);
- else
- result= (unsigned int)b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
- return result;
- }
-
- unsigned short
- swap_short_from_little( void *l)
- {
- unsigned char *b= (unsigned char *) l;
- unsigned short result;
- if ( little_endian)
- memcpy( &result, l, 2);
- else
- result= (unsigned short)b[0] | ((unsigned short)b[1]<<8);
- return result;
- }
-
- #define MAXSTRLEN 2048
-
- char *
- xml_escape( char *string)
- {
- static char _buf[4][MAXSTRLEN];
- static int _buf_index= 0, c;
- char *result, *b;
-
- if ( string == NULL)
- return "";
-
- if ( xml_encoding == ENCODING_LATIN_1 && strpbrk( string, "&<>") == NULL)
- return string;
-
- result= &_buf[_buf_index][0];
- _buf_index= (_buf_index+1) % 4;
-
- b= result;
- for ( ; *string; string++) {
- c= *string;
- switch ( c) {
- case '&':
- *b++= '&';
- *b++= 'a';
- *b++= 'm';
- *b++= 'p';
- *b++= ';';
- continue;
- case '<':
- *b++= '&';
- *b++= 'l';
- *b++= 't';
- *b++= ';';
- continue;
- case '>':
- *b++= '&';
- *b++= 'g';
- *b++= 't';
- *b++= ';';
- continue;
- default:
- break;
- }
- if ( xml_encoding == ENCODING_LATIN_1) {
- if ( isprint(c))
- *b++= c;
- else
- b+= sprintf( b, "%u;", c);
- }
- else if ( xml_encoding == ENCODING_UTF_8) {
- if ( (c & 0x80) == 0)
- *b++= c;
- else {
- *b++= 0xC0 | (0x03 & (c >> 6)) ;
- *b++= 0x80 | (0x3F & c) ;
- }
- }
- }
- *b= '\0';
- return result;
- }
-
-
- static char *quake3_escape_colors[8] = {
- "black", "red", "green", "yellow", "blue", "cyan", "magenta", "white"
- };
-
- static char *sof_colors[32] = {
- "FFFFFF","FFFFFF","FF0000","00FF00","FFFF00","0000FF","FF00FF","00FFFF",
- "000000","7F7F7F","702D07","7F0000","007F00","FFFFFF","007F7F","00007F",
- "564D28","4C5E36","370B65","005572","54647E","1E2A63","66097B","705E61",
- "980053","960018","702D07","54492A","61A997","CB8F39","CF8316","FF8020"
- };
-
-
- char *
- xform_name( char *string, struct qserver *server)
- {
- static char _buf1[1024], _buf2[1024];
- static char *_q= &_buf1[0];
- unsigned char *s= (unsigned char*) string;
- char *q;
- int is_server_name= (string == server->server_name);
- int font_tag= 0;
-
- _q= _q == _buf1 ? _buf2 : _buf1;
- q= _q;
-
- if ( s == NULL) {
- q[0]= '?';
- q[1]= '\0';
- return _q;
- }
-
- if ( hex_player_names && !is_server_name) {
- for ( ; *s; s++, q+= 2)
- sprintf( q, "%02x", *s);
- *q= '\0';
- return _q;
- }
-
- if ( server->type->flags & TF_QUAKE3_NAMES) {
- for ( ; *s; s++) {
- if ( *s == '^' && *(s+1) != '^') {
- if ( *(s+1) == '\0') break;
- if ( html_names == 1) {
- q+= sprintf( q, "%s<font color=\"%s\">",
- font_tag?"</font>":"",
- quake3_escape_colors[ *(s+1) & 0x7]);
- s++;
- font_tag= 1;
- }
- else if ( strip_carets)
- s++;
- else
- *q++= *s;
- }
- else if ( html_mode && *s == '<') {
- strcpy( q, "<");
- q+= 4;
- }
- else if ( html_mode && *s == '>') {
- strcpy( q, ">");
- q+= 4;
- }
- else if ( html_mode && *s == '&') {
- strcpy( q, "&");
- q+= 5;
- }
- else if ( isprint(*s))
- *q++= *s;
- else if ( *s == '\033')
- ;
- else if ( *s == 0x80)
- *q++= '(';
- else if ( *s == 0x81)
- *q++= '=';
- else if ( *s == 0x82)
- *q++= ')';
- else if ( *s == 0x10 || *s == 0x90)
- *q++= '[';
- else if ( *s == 0x11 || *s == 0x91)
- *q++= ']';
- else if ( *s >= 0x92 && *s <= 0x9a)
- *q++= *s - 98;
- else if ( *s >= 0xa0 && *s <= 0xe0)
- *q++= *s - 128;
- else if ( *s >= 0xe1 && *s <= 0xfa)
- *q++= *s - 160;
- else if ( *s >= 0xfb && *s <= 0xfe)
- *q++= *s - 128;
- }
- *q= '\0';
- }
- else if ( !is_server_name && (server->type->flags & TF_TRIBES2_NAMES)) {
- for ( ; *s; s++) {
- if ( html_mode && *s == '<') {
- strcpy( q, "<");
- q+= 4;
- continue;
- }
- else if ( html_mode && *s == '>') {
- strcpy( q, ">");
- q+= 4;
- continue;
- }
- else if ( html_mode && *s == '&') {
- strcpy( q, "&");
- q+= 5;
- continue;
- }
- else if ( isprint(*s)) {
- *q++= *s;
- continue;
- }
- if ( html_names == 1 && s[1] != '\0') {
- char *font_color;
- switch( *s) {
- case 0x8: font_color= "white"; break; /* normal */
- case 0xb: font_color= "yellow"; break; /* tribe tag */
- case 0xc: font_color= "blue"; break; /* alias */
- case 0xe: font_color= "green"; break; /* bot */
- default: font_color= NULL;
- }
- if ( font_color) {
- q+= sprintf( q, "%s<font color=\"%s\">",
- font_tag?"</font>":"",
- font_color);
- font_tag= 1;
- }
- }
- }
- *q= '\0';
- }
- else if ( !is_server_name || (server->type->flags & TF_SOF_NAMES)) {
- for ( ; *s; s++) {
- if ( html_mode && *s == '<') {
- strcpy( q, "<");
- q+= 4;
- continue;
- }
- else if ( html_mode && *s == '>') {
- strcpy( q, ">");
- q+= 4;
- continue;
- }
- else if ( html_mode && *s == '&') {
- strcpy( q, "&");
- q+= 5;
- continue;
- }
-
- if ( *s < ' ' ) {
- if ( html_names == 1) {
- q+= sprintf( q, "%s<font color=\"#%s\">",
- font_tag?"</font>":"",
- sof_colors[ *(s) ]);
- font_tag= 1;
- }
- }
- else if ( isprint(*s))
- *q++= *s;
- /* ## more fixes below; double check against real sof servers */
- else if ( *s >= 0xa0)
- *q++= *s & 0x7f;
- else if ( *s >= 0x92 && *s < 0x9c)
- *q++= '0' + (*s - 0x92);
- else if ( *s >= 0x12 && *s < 0x1c)
- *q++= '0' + (*s - 0x12);
- else if ( *s == 0x90 || *s == 0x10)
- *q++= '[';
- else if ( *s == 0x91 || *s == 0x11)
- *q++= ']';
- else if ( *s == 0xa || *s == 0xc || *s == 0xd)
- *q++= ']';
- }
- *q= '\0';
- }
- else
- strcpy( _q, string);
-
- if ( font_tag)
- q+= sprintf( q, "</font>");
-
- return _q;
-
- }
-
- int
- is_default_rule( struct rule *rule)
- {
- if ( strcmp( rule->name, "sv_maxspeed") == 0)
- return strcmp( rule->value, Q_DEFAULT_SV_MAXSPEED) == 0;
- if ( strcmp( rule->name, "sv_friction") == 0)
- return strcmp( rule->value, Q_DEFAULT_SV_FRICTION) == 0;
- if ( strcmp( rule->name, "sv_gravity") == 0)
- return strcmp( rule->value, Q_DEFAULT_SV_GRAVITY) == 0;
- if ( strcmp( rule->name, "noexit") == 0)
- return strcmp( rule->value, Q_DEFAULT_NOEXIT) == 0;
- if ( strcmp( rule->name, "teamplay") == 0)
- return strcmp( rule->value, Q_DEFAULT_TEAMPLAY) == 0;
- if ( strcmp( rule->name, "timelimit") == 0)
- return strcmp( rule->value, Q_DEFAULT_TIMELIMIT) == 0;
- if ( strcmp( rule->name, "fraglimit") == 0)
- return strcmp( rule->value, Q_DEFAULT_FRAGLIMIT) == 0;
- return 0;
- }
-
- char *
- strherror( int h_err)
- {
- static char msg[100];
- switch (h_err) {
- case HOST_NOT_FOUND: return "host not found";
- case TRY_AGAIN: return "try again";
- case NO_RECOVERY: return "no recovery";
- case NO_ADDRESS: return "no address";
- default: sprintf( msg, "%d", h_err); return msg;
- }
- }
-
- int
- time_delta( struct timeval *later, struct timeval *past)
- {
- if ( later->tv_usec < past->tv_usec) {
- later->tv_sec--;
- later->tv_usec+= 1000000;
- }
- return (later->tv_sec - past->tv_sec) * 1000 +
- (later->tv_usec - past->tv_usec) / 1000;
- }
-
- int
- connection_refused()
- {
- #ifdef _ISUNIX
- return errno == ECONNREFUSED;
- #endif
-
- #ifdef _WIN32
- return WSAGetLastError() == WSAECONNABORTED;
- #endif
- }
-
- void
- set_non_blocking( int fd)
- {
- #ifdef _ISUNIX
- #ifdef O_NONBLOCK
- fcntl( fd, F_SETFL, O_NONBLOCK);
- #else
- fcntl( fd, F_SETFL, O_NDELAY);
- #endif
- #endif
-
- #ifdef _WIN32
- int one= 1;
- ioctlsocket( fd, FIONBIO, (unsigned long*)&one);
- #endif
- }
-
- void
- print_packet( struct qserver *server, char *buf, int buflen)
- {
- static char *hex= "0123456789abcdef";
- unsigned char *p= (unsigned char*)buf;
- int i, h, a, b, offset= 0;
- char line[256];
-
- if ( server != NULL)
- fprintf( stderr, "FROM %s\n", server->arg);
-
- for ( i= buflen; i ; offset+= 16) {
- memset( line, ' ', 256);
- h= 0;
- h+= sprintf( line, "%5d:", offset);
- a= h + 16*2 + 16/4 + 2;
- for ( b=16; b && i; b--, i--, p++) {
- if ( (b & 3) == 0)
- line[h++]= ' ';
- line[h++]= hex[*p >> 4];
- line[h++]= hex[*p & 0xf];
- if ( isprint( *p))
- line[a++]= *p;
- else
- line[a++]= '.';
- }
- line[a]= '\0';
- fputs( line, stderr);
- fputs( "\n", stderr);
- }
- fputs( "\n", stderr);
- }
-
- char *
- quake_color( int color)
- {
- static char *colors[] = {
- "White", /* 0 */
- "Brown", /* 1 */
- "Lavender", /* 2 */
- "Khaki", /* 3 */
- "Red", /* 4 */
- "Lt Brown", /* 5 */
- "Peach", /* 6 */
- "Lt Peach", /* 7 */
- "Purple", /* 8 */
- "Dk Purple", /* 9 */
- "Tan", /* 10 */
- "Green", /* 11 */
- "Yellow", /* 12 */
- "Blue", /* 13 */
- "Blue", /* 14 */
- "Blue" /* 15 */
- };
-
- static char *rgb_colors[] = {
- "#ffffff", /* 0 */
- "#8b4513", /* 1 */
- "#e6e6fa", /* 2 */
- "#f0e68c", /* 3 */
- "#ff0000", /* 4 */
- "#deb887", /* 5 */
- "#eecbad", /* 6 */
- "#ffdab9", /* 7 */
- "#9370db", /* 8 */
- "#5d478b", /* 9 */
- "#d2b48c", /* 10 */
- "#00ff00", /* 11 */
- "#ffff00", /* 12 */
- "#0000ff", /* 13 */
- "#0000ff", /* 14 */
- "#0000ff" /* 15 */
- };
-
- if ( color_names) {
- if ( color_names == 1)
- return colors[color&0xf];
- else
- return rgb_colors[color&0xf];
- }
- else
- return (char*)color;
- }
-
- char *
- play_time( int seconds, int show_seconds)
- {
- static char time_string[24];
- if ( time_format == CLOCK_TIME) {
- time_string[0]= '\0';
- if ( seconds/3600)
- sprintf( time_string, "%2dh", seconds/3600);
- else
- strcat( time_string, " ");
- if ( (seconds%3600)/60 || seconds/3600)
- sprintf( time_string+strlen(time_string), "%2dm",
- (seconds%3600)/60);
- else if ( ! show_seconds)
- sprintf( time_string+strlen(time_string), " 0m");
- else
- strcat( time_string, " ");
- if ( show_seconds)
- sprintf( time_string+strlen(time_string), "%2ds", seconds%60);
- }
- else if ( time_format == STOPWATCH_TIME) {
- if ( show_seconds)
- sprintf( time_string, "%02d:%02d:%02d", seconds/3600,
- (seconds%3600)/60, seconds % 60);
- else
- sprintf( time_string, "%02d:%02d", seconds/3600,
- (seconds%3600)/60);
- }
- else
- sprintf( time_string, "%d", seconds);
-
- return time_string;
- }
-
- char *
- ping_time( int ms)
- {
- static char time_string[24];
- if ( ms < 1000)
- sprintf( time_string, "%dms", ms);
- else if ( ms < 1000000)
- sprintf( time_string, "%ds", ms/1000);
- else
- sprintf( time_string, "%dm", ms/1000/60);
- return time_string;
- }
-
- int
- count_bits( int n)
- {
- int b= 0;
- for ( ; n; n>>=1)
- if ( n&1)
- b++;
- return b;
- }
-
- int
- strcmp_withnull( char *one, char *two)
- {
- if ( one == NULL && two == NULL)
- return 0;
- if ( one != NULL && two == NULL)
- return -1;
- if ( one == NULL)
- return 1;
- return strcasecmp( one, two);
- }
-
- /*
- * Sorting functions
- */
-
- void quicksort( void **array, int i, int j, int (*compare)(void*,void*));
- int qpartition( void **array, int i, int j, int (*compare)(void*,void*));
-
- void
- sort_servers( struct qserver **array, int size)
- {
- quicksort( (void**)array, 0, size-1, (int (*)(void*,void*)) server_compare);
- }
-
- void
- sort_players( struct qserver *server)
- {
- struct player **array, *player, *last_team= NULL, **next;
- int np, i;
-
- if ( server->num_players == 0 || server->players == NULL)
- return;
-
- player= server->players;
- for ( ; player != NULL && player->number == TRIBES_TEAM; ) {
- last_team= player;
- player= player->next;
- }
- if ( player == NULL)
- return;
-
- array= (struct player **) malloc( sizeof(struct player *) *
- server->num_players);
- for ( np= 0; player != NULL && np < server->num_players; np++) {
- array[np]= player;
- player= player->next;
- }
- quicksort( (void**)array, 0, np-1, (int (*)(void*,void*)) player_compare);
-
- if ( last_team)
- next= &last_team->next;
- else
- next= &server->players;
-
- for ( i= 0; i < np; i++) {
- *next= array[i];
- array[i]->next= NULL;
- next= &array[i]->next;
- }
-
- free( array);
- }
-
- int
- server_compare( struct qserver *one, struct qserver *two)
- {
- int rc;
-
- char *key= sort_keys;
-
- for ( ; *key; key++) {
- switch( *key) {
- case 'g':
- rc= strcmp_withnull( one->game, two->game);
- if ( rc)
- return rc;
- break;
- case 'p':
- if ( one->n_requests == 0)
- return two->n_requests;
- else if ( two->n_requests == 0)
- return -1;
- rc= one->ping_total/one->n_requests -
- two->ping_total/two->n_requests;
- if ( rc)
- return rc;
- break;
- case 'i':
- if ( one->ipaddr > two->ipaddr)
- return 1;
- else if ( one->ipaddr < two->ipaddr)
- return -1;
- else if ( one->port > two->port)
- return 1;
- else if ( one->port < two->port)
- return -1;
- break;
- case 'h':
- rc= strcmp_withnull( one->host_name, two->host_name);
- if ( rc)
- return rc;
- break;
- case 'n':
- rc= two->num_players - one->num_players;
- if ( rc)
- return rc;
- break;
- }
- }
-
- return 0;
- }
-
- int
- player_compare( struct player *one, struct player *two)
- {
- int rc;
-
- char *key= sort_keys;
-
- for ( ; *key; key++) {
- switch( *key) {
- case 'P':
- rc= one->ping - two->ping;
- if ( rc)
- return rc;
- break;
- case 'F':
- rc= two->frags - one->frags;
- if ( rc)
- return rc;
- break;
- case 'T':
- rc= one->team - two->team;
- if ( rc)
- return rc;
- break;
- }
- }
- return 0;
- }
-
- void
- quicksort( void **array, int i, int j, int (*compare)(void*,void*))
- {
- int q= 0;
-
- if ( i < j) {
- q = qpartition(array,i,j, compare);
- quicksort(array,i,q, compare);
- quicksort(array,q+1,j, compare);
- }
- }
-
- int
- qpartition( void **array, int a, int b, int (*compare)(void*,void*))
- {
- /* this is our comparison point. when we are done
- splitting this array into 2 parts, we want all the
- elements on the left side to be less then or equal
- to this, all the elements on the right side need to
- be greater then or equal to this
- */
- void *z;
-
- /* indicies into the array to sort. Used to calculate a partition
- point
- */
- int i = a-1;
- int j = b+1;
-
- /* temp pointer used to swap two array elements */
- void * tmp = NULL;
-
- z = array[a];
-
- while (1) {
-
- /* move the right indice over until the value of that array
- elem is less than or equal to z. Stop if we hit the left
- side of the array (ie, j == a);
- */
- do {
- j--;
- } while( j > a && compare(array[j],z) > 0);
-
- /* move the left indice over until the value of that
- array elem is greater than or equal to z, or until
- we hit the right side of the array (ie i == j)
- */
- do {
- i++;
- } while( i <= j && compare(array[i],z) < 0);
-
- /* if i is less then j, we need to switch those two array
- elements, if not then we are done partitioning this array
- section
- */
- if(i < j) {
- tmp = array[i];
- array[i] = array[j];
- array[j] = tmp;
- }
- else
- return j;
- }
- }
-
-